AC_PROG_CC_C99
+AC_ARG_WITH([gobject],
+ [AS_HELP_STRING([--with-gobject],
+ [build tools requiring libgobject [default=yes]]
+ )],
+ [],
+ [with_gobject=yes])
+
+have_gobject=no
+if test x$with_gobject = xyes; then
+AM_PATH_GLIB_2_0(, [have_gobject=yes], [have_gobject=no], [gobject])
+fi
+
+AM_CONDITIONAL([BUILD_UPKG], [test x$have_gobject = xyes])
+
LT_INIT
AC_CONFIG_FILES([
lib_LTLIBRARIES = libupkg.la
-bin_PROGRAMS = upkg
libupkg_la_SOURCES = libupkg.c pack.c
include_HEADERS = upkg.h
noinst_HEADERS = pack.h
-upkg_SOURCES = upkg.c
+if BUILD_UPKG
+bin_PROGRAMS = upkg
+upkg_SOURCES = upkg.c exportable.c serializable.c music.c
+upkg_CFLAGS = $(GLIB_CFLAGS)
+upkg_LDFLAGS = $(GLIB_LIBS)
upkg_LDADD = libupkg.la
+endif
--- /dev/null
+#include <stdio.h>
+#include <glib-object.h>
+#include "exportable.h"
+
+GType upkg_exportable_get_type(void)
+{
+ static GType type = 0;
+ if (type == 0) {
+ static const GTypeInfo info = {
+ sizeof (UPkgExportable),
+ NULL,
+ NULL,
+ };
+
+ type = g_type_register_static(G_TYPE_INTERFACE,
+ "UPkgExportable", &info, 0);
+ }
+ return type;
+}
+
+int upkg_export(GObject *obj, FILE *f)
+{
+ g_return_val_if_fail(UPKG_IS_EXPORTABLE(obj), -1);
+ return UPKG_EXPORTABLE_GET_INTERFACE(obj)->export(obj, f);
+}
+
+int upkg_export_name(GObject *obj, char *buf, size_t n)
+{
+ g_return_val_if_fail(UPKG_IS_EXPORTABLE(obj), -1);
+ return UPKG_EXPORTABLE_GET_INTERFACE(obj)->export_name(obj, buf, n);
+}
--- /dev/null
+#ifndef EXPORTABLE_H_
+#define EXPORTABLE_H_
+
+#include <stdio.h>
+#include <glib-object.h>
+
+#define UPKG_TYPE_EXPORTABLE (upkg_exportable_get_type())
+#define UPKG_EXPORTABLE(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, \
+ UPKG_TYPE_EXPORTABLE, UPkgExportable)
+#define UPKG_IS_EXPORTABLE(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, \
+ UPKG_TYPE_EXPORTABLE)
+#define UPKG_EXPORTABLE_GET_INTERFACE(inst) G_TYPE_INSTANCE_GET_INTERFACE \
+ (inst, UPKG_TYPE_EXPORTABLE, UPkgExportable)
+
+typedef struct UPkgExportable UPkgExportable;
+
+struct UPkgExportable {
+ GTypeInterface parent;
+
+ int (*export)(GObject *obj, FILE *f);
+ int (*export_name)(GObject *obj, char *buf, size_t n);
+};
+
+GType upkg_exportable_get_type(void);
+
+int upkg_export(GObject *obj, FILE *f);
+int upkg_export_name(GObject *obj, char *buf, size_t n);
+
+#endif
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include <glib-object.h>
+
+#include "serializable.h"
+#include "exportable.h"
+#include "music.h"
+#include "upkg.h"
+
+#define U_MUSIC_GET_PRIV(o) \
+ G_TYPE_INSTANCE_GET_PRIVATE(o, U_MUSIC_TYPE, struct music_priv)
+
+struct music_priv {
+ unsigned type;
+
+ struct upkg_file *f;
+ size_t base, len;
+
+ unsigned char buf[2048];
+ unsigned long nbuf;
+};
+
+static void serializable_init(UPkgSerializable *s);
+static void exportable_init(UPkgExportable *e);
+
+G_DEFINE_TYPE_WITH_CODE(UMusic, u_music, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE(UPKG_TYPE_SERIALIZABLE, serializable_init)
+ G_IMPLEMENT_INTERFACE(UPKG_TYPE_EXPORTABLE, exportable_init)
+);
+
+static int export(GObject *o, FILE *f)
+{
+ struct music_priv *priv = U_MUSIC_GET_PRIV(o);
+ size_t left = priv->len, rc;
+
+ unsigned char buf[1024];
+
+ if (upkg_export_seek(priv->f, priv->base, SEEK_SET) != 0)
+ return -1;
+
+ while (left > 0) {
+ rc = upkg_export_read(priv->f, buf, MIN(left, sizeof buf));
+ if (rc == 0)
+ return -1;
+ if (fwrite(buf, 1, rc, f) != rc)
+ return -1;
+ left -= rc;
+ }
+
+ return 0;
+}
+
+static int export_name(GObject *o, char *buf, size_t n)
+{
+ struct music_priv *priv = U_MUSIC_GET_PRIV(o);
+
+ return snprintf(buf, n, "%s", priv->f->name);
+}
+
+static void exportable_init(UPkgExportable *e)
+{
+ e->export = export;
+ e->export_name = export_name;
+}
+
+static int deserialize(GObject *o, struct upkg_file *f)
+{
+ struct music_priv *priv = U_MUSIC_GET_PRIV(o);
+ UMusic *m = U_MUSIC(o);
+ long size;
+
+ size_t rc;
+
+ priv->nbuf = upkg_export_read(f, priv->buf, sizeof priv->buf);
+ priv->base = 0;
+
+ /* Random field #1 */
+ if (priv->nbuf - priv->base < 2)
+ return -1;
+ // unpack_16_le(priv->buf+0);
+ priv->base += 2;
+
+ if (f->pkg->version > 61) {
+ /* Random field #2 */
+ if (priv->nbuf - priv->base < 4)
+ return -1;
+ // unpack_32_le(priv->buf+2);
+ priv->base += 4;
+ }
+
+ rc = upkg_decode_index(&size, priv->buf+priv->base, priv->nbuf-priv->base);
+ if (rc == 0 || size < 0)
+ return -1;
+
+ priv->base += rc;
+ priv->len = size;
+
+ priv->nbuf -= priv->base;
+ memmove(priv->buf, priv->buf+priv->base, priv->nbuf);
+
+ priv->f = f;
+ return 0;
+}
+
+static void serializable_init(UPkgSerializable *s)
+{
+ s->deserialize = deserialize;
+}
+
+static void u_music_init(UMusic *o)
+{
+}
+
+static void u_music_class_init(UMusicClass *class)
+{
+ g_type_class_add_private(class, sizeof (struct music_priv));
+}
--- /dev/null
+#ifndef MUSIC_H_
+#define MUSIC_H_
+
+#include <glib-object.h>
+
+#define U_MUSIC_TYPE (u_music_get_type())
+#define U_MUSIC(obj) \
+ G_TYPE_CHECK_INSTANCE_CAST(obj, U_MUSIC_TYPE, UMusic)
+#define U_MUSIC_CLASS(class) \
+ G_TYPE_CHECK_CLASS_CAST(class, U_MUSIC_TYPE, UMusicClass)
+#define IS_U_MUSIC(obj) \
+ G_TYPE_CHECK_INSTANCE_TYPE(obj, U_MUSIC_TYPE)
+#define IS_U_MUSIC_CLASS(class) \
+ G_TYPE_CHECK_CLASS_TYPE(class, U_MUSIC_TYPE, UMusicClass)
+
+typedef struct UMusic UMusic;
+typedef struct UMusicClass UMusicClass;
+
+enum {
+ U_MUSIC_UNKNOWN,
+ U_MUSIC_IT,
+ U_MUSIC_S3M,
+ U_MUSIC_XM,
+};
+
+struct UMusic {
+ GObject parent;
+};
+
+struct UMusicClass {
+ GObjectClass parent;
+};
+
+GType u_music_get_type(void);
+
+static inline GObject *u_music_new(void)
+{
+ return g_object_new(u_music_get_type(), NULL);
+}
+
+#endif
--- /dev/null
+#include <glib-object.h>
+#include "serializable.h"
+#include "upkg.h"
+
+GType upkg_serializable_get_type(void)
+{
+ static GType type = 0;
+ if (type == 0) {
+ static const GTypeInfo info = {
+ sizeof (UPkgSerializable),
+ NULL,
+ NULL,
+ };
+
+ type = g_type_register_static(G_TYPE_INTERFACE,
+ "UPkgSerializable", &info, 0);
+ }
+ return type;
+}
+
+int upkg_deserialize(GObject *obj, struct upkg_file *f)
+{
+ g_return_val_if_fail(UPKG_IS_SERIALIZABLE(obj), -1);
+ return UPKG_SERIALIZABLE_GET_INTERFACE(obj)->deserialize(obj, f);
+}
--- /dev/null
+#ifndef SERIALIZABLE_H_
+#define SERIALIZABLE_H_
+
+#include <glib-object.h>
+#include "upkg.h"
+
+#define UPKG_TYPE_SERIALIZABLE (upkg_serializable_get_type())
+#define UPKG_SERIALIZABLE(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, \
+ UPKG_TYPE_SERIALIZABLE, UPkgSerializable)
+#define UPKG_IS_SERIALIZABLE(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, \
+ UPKG_TYPE_SERIALIZABLE)
+#define UPKG_SERIALIZABLE_GET_INTERFACE(inst) G_TYPE_INSTANCE_GET_INTERFACE \
+ (inst, UPKG_TYPE_SERIALIZABLE, UPkgSerializable)
+
+typedef struct UPkgSerializable UPkgSerializable;
+
+struct UPkgSerializable {
+ GTypeInterface parent;
+
+ int (*deserialize)(GObject *obj, struct upkg_file *f);
+};
+
+GType upkg_serializable_get_type(void);
+int upkg_deserialize(GObject *obj, struct upkg_file *f);
+
+#endif
#include <stdio.h>
#include <stdlib.h>
+#include <glib-object.h>
+
#include "upkg.h"
+#include "serializable.h"
+#include "exportable.h"
+#include "music.h"
void print_upkg_flags(const char *prefix, unsigned long flags)
{
{
struct upkg *pkg;
+ g_type_init();
+
if (argc < 2) {
fprintf(stderr, "usage: upkg file\n");
return EXIT_FAILURE;
printf("Exports: %lu\n", pkg->export_count);
printf("Imports: %lu\n", pkg->import_count);
+ GObject *music = u_music_new();
+ struct upkg_file *f = upkg_export_open(pkg, 0);
+ upkg_deserialize(music, f);
+
+ char name[256];
+ upkg_export_name(music, name, sizeof name);
+ FILE *fp = fopen(name, "wb");
+ if (!fp) return EXIT_FAILURE;
+ upkg_export(music, fp);
+ fclose(fp);
+ printf("Wrote %s\n", name);
+
upkg_close(pkg);
return 0;
}