]> git.draconx.ca Git - upkg.git/blob - src/uobject/package.c
397d2638df34c2e59e024ef7e309c9c9891f2a23
[upkg.git] / src / uobject / package.c
1 /*
2  *  upkg: tool for manipulating Unreal Tournament packages.
3  *  Copyright (C) 2009 Nick Bowler
4  *
5  *  This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <ctype.h>
23
24 #include <glib-object.h>
25 #include <ltdl.h>
26
27 #include <uobject/package.h>
28 #include <uobject/vfs.h>
29 #include "upkg.h"
30
31 #define U_PKG_GET_PRIV(o) \
32         G_TYPE_INSTANCE_GET_PRIVATE(o, U_PKG_TYPE, struct upkg_priv)
33
34 struct upkg_priv {
35         lt_dlhandle native;
36 };
37
38 G_DEFINE_TYPE(UPkg, u_pkg, G_TYPE_TYPE_MODULE);
39
40 static char *str_cpy_lower(char *dst, const char *src)
41 {
42         size_t i;
43
44         for (i = 0; src[i]; i++)
45                 dst[i] = tolower(src[i]);
46         dst[i] = 0;
47
48         return dst;
49 }
50
51 static void dl_print_errors(const char *prefix)
52 {
53         const char *err;
54         while ((err = lt_dlerror())) {
55                 if (prefix) fprintf(stderr, "%s: ", prefix);
56                 fprintf(stderr, "%s\n", err);
57         }
58 }
59
60 static gboolean u_pkg_load(GTypeModule *m)
61 {
62         struct upkg_priv *priv = U_PKG_GET_PRIV(m);
63         int (*init_func)(GTypeModule *);
64
65         /* Ignore failure here until we get rid of native-only packages. */
66         U_PKG(m)->pkg = u_pkg_vfs_open_by_name(m->name);
67
68         priv->native = lt_dlopenext(m->name);
69         if (priv->native) {
70                 init_func = lt_dlsym(priv->native, "init");
71                 if (!init_func || init_func(m) != 0) {
72                         dl_print_errors(__func__);
73                         lt_dlclose(priv->native);
74                         upkg_close(U_PKG(m)->pkg);
75                         return FALSE;
76                 }
77         }
78
79         return TRUE;
80 }
81
82 static void u_pkg_unload(GTypeModule *m)
83 {
84         struct upkg_priv *priv = U_PKG_GET_PRIV(m);
85         void (*exit_func)(GTypeModule *);
86         UPkg *upkg = U_PKG(m);
87
88         if (priv->native) {
89                 exit_func = lt_dlsym(priv->native, "exit");
90                 if (exit_func) {
91                         exit_func(m);
92                 }
93
94                 if (lt_dlclose(priv->native) != 0) {
95                         dl_print_errors(__func__);
96                 }
97
98                 priv->native = NULL;
99         }
100
101         if (upkg->pkg) {
102                 upkg_close(upkg->pkg);
103                 upkg->pkg = NULL;
104         }
105 }
106
107 static void u_pkg_init(UPkg *pkg)
108 {
109
110 }
111
112 static void u_pkg_finalize(GObject *o)
113 {
114         u_pkg_unload(G_TYPE_MODULE(o));
115 }
116
117 static void u_pkg_class_init(UPkgClass *class)
118 {
119         GTypeModuleClass *modclass = G_TYPE_MODULE_CLASS(class);
120         GObjectClass *objclass = G_OBJECT_CLASS(class);
121
122         const char *modpath = getenv("UOBJECT_MODULE_PATH");
123
124         g_type_class_add_private(class, sizeof (struct upkg_priv));
125
126         if (lt_dlinit() != 0) {
127                 dl_print_errors(__func__);
128         }
129
130         if (modpath && lt_dlsetsearchpath(modpath) != 0) {
131                 dl_print_errors(__func__);
132         }
133         if (lt_dladdsearchdir(PKGLIBDIR) != 0) {
134                 dl_print_errors(__func__);
135         }
136
137         modclass->load     = u_pkg_load;
138         modclass->unload   = u_pkg_unload;
139         objclass->finalize = u_pkg_finalize;
140 }
141
142 GTypeModule *u_pkg_open(const char *name)
143 {
144         g_return_val_if_fail(name != NULL, NULL);
145
146         char *pkgname = malloc(strlen(name)+1);
147         if (!pkgname) {
148                 return NULL;
149         }
150
151         GTypeModule *mod = g_object_new(U_PKG_TYPE, NULL);
152         if (!mod) {
153                 free(pkgname);
154                 return NULL;
155         }
156
157         mod->name = str_cpy_lower(pkgname, name);
158         return mod;
159 }