Add Bocfel interpreter
[projects/chimara/chimara.git] / interpreters / bocfel / iff.c
diff --git a/interpreters/bocfel/iff.c b/interpreters/bocfel/iff.c
new file mode 100644 (file)
index 0000000..e7fe4e1
--- /dev/null
@@ -0,0 +1,112 @@
+/*-
+ * Copyright 2010-2012 Chris Spiegel.
+ *
+ * This file is part of Bocfel.
+ *
+ * Bocfel is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version
+ * 2 or 3, as published by the Free Software Foundation.
+ *
+ * Bocfel 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 Bocfel.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "iff.h"
+#include "io.h"
+
+struct zterp_iff
+{
+  zterp_io *io;
+  uint32_t tag;
+  long offset;
+  uint32_t size;
+
+  struct zterp_iff *next;
+};
+
+void zterp_iff_free(zterp_iff *iff)
+{
+  while(iff != NULL)
+  {
+    zterp_iff *tmp = iff->next;
+    free(iff);
+    iff = tmp;
+  }
+}
+
+zterp_iff *zterp_iff_parse(zterp_io *io, const char type[4])
+{
+  uint32_t tag;
+
+  zterp_iff *iff = NULL, *tail = NULL;
+
+  if(zterp_io_seek(io, 0, SEEK_SET) == -1) goto err;
+
+  if(!zterp_io_read32(io, &tag) || tag != STRID("FORM")) goto err;
+
+  if(zterp_io_seek(io, 4, SEEK_CUR) == -1) goto err;
+
+  if(!zterp_io_read32(io, &tag) || tag != STRID(type)) goto err;
+
+  while(zterp_io_read32(io, &tag))
+  {
+    uint32_t size;
+    zterp_iff *new;
+
+    if(!zterp_io_read32(io, &size)) goto err;
+
+    new = malloc(sizeof *new);
+    if(new == NULL) goto err;
+
+    new->tag = tag;
+    new->io = io;
+    new->offset = zterp_io_tell(io);
+    new->size = size;
+    new->next = NULL;
+
+    if(iff == NULL) iff = new;
+    else            tail->next = new;
+
+    tail = new;
+
+    if(new->offset == -1) goto err;
+
+    if(size & 1) size++;
+
+    if(zterp_io_seek(io, size, SEEK_CUR) == -1) goto err;
+  }
+
+  return iff;
+
+err:
+  zterp_iff_free(iff);
+
+  return NULL;
+}
+
+int zterp_iff_find(zterp_iff *iff, const char tag[4], uint32_t *size)
+{
+  while(iff != NULL)
+  {
+    if(iff->tag == STRID(tag))
+    {
+      if(zterp_io_seek(iff->io, iff->offset, SEEK_SET) == -1) return 0;
+      *size = iff->size;
+
+      return 1;
+    }
+
+    iff = iff->next;
+  }
+
+  return 0;
+}