Force 'captivemodid' checking during any W32 module loading.
[captive.git] / src / libcaptive / captivemodid / captivemodid.c
index 8aceea4..3344896 100644 (file)
 #include <ctype.h>
 
 
-gchar *captive_calc_md5(gconstpointer base,size_t length)
+struct _CaptiveCaptivemodidObject {
+       GObject parent_instance;
+
+       /* map: GINT_TO_POINTER(captive_captivemodid_module.length) -> !=NULL */
+       /* No allocations needed. */
+       GHashTable *module_valid_length_hash;
+
+       /* map: (const xmlChar *)md5 -> (struct captive_captivemodid_module *) */
+       /* 'key' is not allocated it is shared with: 'val'->md5 */
+       /* 'val' is allocated, to be automatically freed by: captive_captivemodid_module_free() */
+       GHashTable *module_md5_hash;
+
+       /* map: (const xmlChar *)type -> (gpointer)GINT_TO_POINTER(priority) */
+       /* We remove entry for module with already the best priority found,
+        * therefore captive_captivemodid_module_type_best_priority_lookup() will return
+        * 'G_MININT' afterwards.
+        * 'key' is not allocated - it is shared with: module_md5_hash */
+       /* No allocations needed. */
+       GHashTable *module_type_best_priority_hash;
+
+       /* g_strdup()ped */
+       gchar *pathname_loaded;
+       };
+struct _CaptiveCaptivemodidObjectClass {
+       GObjectClass parent_class;
+       };
+
+
+static gpointer captive_captivemodid_object_parent_class=NULL;
+
+
+static void captive_captivemodid_object_finalize(CaptiveCaptivemodidObject *captive_captivemodid_object)
 {
-unsigned char md5_bin[1+128/8];        /* 128 bits==16 bytes; '1+' for leading stub to prevent shorter output of BN_bn2hex() */
-BIGNUM *bignum;
-char *hex;
-gchar *r,*gs;
+       g_return_if_fail(captive_captivemodid_object!=NULL);
 
-       /* already done above */
-       /* Calculate MD5 sum and convert it to hex string: */
-       MD5(base,length,md5_bin+1);
-       md5_bin[0]=0xFF;  /* stub to prevent shorter output of BN_bn2hex() */
-       bignum=BN_bin2bn(md5_bin,1+128/8,NULL);
-       hex=BN_bn2hex(bignum);
-       g_assert(strlen(hex)==2*(1+128/8));
-       r=g_strdup(hex+2);
-       OPENSSL_free(hex);
-       BN_free(bignum);
+       g_hash_table_destroy(captive_captivemodid_object->module_valid_length_hash);
+       g_hash_table_destroy(captive_captivemodid_object->module_md5_hash);
+       g_hash_table_destroy(captive_captivemodid_object->module_type_best_priority_hash);
+       g_free(captive_captivemodid_object->pathname_loaded);
 
-       g_assert(strlen(r)==32);
-       for (gs=r;*gs;gs++) {
-               g_assert(isxdigit(*gs));
-               *gs=tolower(*gs);
-               g_assert(isxdigit(*gs));
-               }
-       return r;
+       G_OBJECT_CLASS(captive_captivemodid_object_parent_class)->finalize((GObject *)captive_captivemodid_object);
 }
 
 
-/* map: GINT_TO_POINTER(captive_captivemodid_module.length) -> !=NULL */
-static GHashTable *module_valid_length_hash;
-
-static void module_valid_length_hash_init(void)
+static void captive_captivemodid_object_class_init(CaptiveCaptivemodidObjectClass *class)
 {
-       if (module_valid_length_hash)
-               return;
-       module_valid_length_hash=g_hash_table_new(g_direct_hash,g_direct_equal);
+GObjectClass *gobject_class=G_OBJECT_CLASS(class);
+
+       captive_captivemodid_object_parent_class=g_type_class_ref(g_type_parent(G_TYPE_FROM_CLASS(class)));
+       gobject_class->finalize=(void (*)(GObject *object))captive_captivemodid_object_finalize;
 }
 
-/* map: (const xmlChar *)md5 -> (struct captive_captivemodid_module *) */
-static GHashTable *module_md5_hash;
 
-static void module_md5_hash_init(void)
+static void captive_captivemodid_module_free(struct captive_captivemodid_module *module)
 {
-       if (module_md5_hash)
-               return;
-       module_md5_hash=g_hash_table_new(g_str_hash,g_str_equal);
+       xmlFree((xmlChar *)module->type);
+       xmlFree((xmlChar *)module->md5);
+       xmlFree((xmlChar *)module->id);
+       g_free(module);
 }
 
-/* map: (const xmlChar *)type -> (gpointer)GINT_TO_POINTER(priority) */
-/* We remove entry for module with already the best priority found,
- * therefore captive_captivemodid_module_type_best_priority_lookup() will return
- * 'G_MININT' afterwards.
- */
-static GHashTable *module_type_best_priority_hash;
+static void captive_captivemodid_object_init(CaptiveCaptivemodidObject *captive_captivemodid_object)
+{
+       captive_captivemodid_object->module_valid_length_hash=g_hash_table_new(g_direct_hash,g_direct_equal);
+       captive_captivemodid_object->module_md5_hash=g_hash_table_new_full(g_str_hash,g_str_equal,
+                       NULL,   /* key_destroy_func */
+                       (GDestroyNotify)captive_captivemodid_module_free);      /* value_destroy_func */
+       captive_captivemodid_object->module_type_best_priority_hash=g_hash_table_new(g_str_hash,g_str_equal);
+}
 
-static void module_type_best_priority_hash_init(void)
+
+GType captive_captivemodid_object_get_type(void)
 {
-       if (module_type_best_priority_hash)
-               return;
-       module_type_best_priority_hash=g_hash_table_new(g_str_hash,g_str_equal);
+static GType captive_captivemodid_object_type=0;
+
+       if (!captive_captivemodid_object_type) {
+static const GTypeInfo captive_captivemodid_object_info={
+                               sizeof(CaptiveCaptivemodidObjectClass),
+                               NULL,   /* base_init */
+                               NULL,   /* base_finalize */
+                               (GClassInitFunc)captive_captivemodid_object_class_init,
+                               NULL,   /* class_finalize */
+                               NULL,   /* class_data */
+                               sizeof(CaptiveCaptivemodidObject),
+                               5,      /* n_preallocs */
+                               (GInstanceInitFunc)captive_captivemodid_object_init,
+                               };
+
+               captive_captivemodid_object_type=g_type_register_static(G_TYPE_OBJECT,
+                               "CaptiveCaptivemodidObject",&captive_captivemodid_object_info,0);
+               }
+
+       return captive_captivemodid_object_type;
 }
 
-static void captive_captivemodid_load_module(struct captive_captivemodid_module *module)
+
+static void captive_captivemodid_load_module
+               (CaptiveCaptivemodidObject *captivemodid,struct captive_captivemodid_module *module)
 {
 struct captive_captivemodid_module *module_md5_conflict;
 gpointer valid_length_value_gpointer;
 
-       module_md5_hash_init();
-       if ((module_md5_conflict=g_hash_table_lookup(module_md5_hash,module->md5))) {
+       if ((module_md5_conflict=g_hash_table_lookup(captivemodid->module_md5_hash,module->md5))) {
                g_warning(_("Ignoring module \"%s\" as it has MD5 conflict with: %s"),
                                module->id,module_md5_conflict->id);
                return;
                }
-       g_hash_table_insert(module_md5_hash,(/* de-const */ xmlChar *)module->md5,module);
+       g_hash_table_insert(captivemodid->module_md5_hash,(/* de-const */ xmlChar *)module->md5,module);
 
-       module_valid_length_hash_init();
-       if (!g_hash_table_lookup_extended(module_valid_length_hash,GINT_TO_POINTER(module->length),
+       if (!g_hash_table_lookup_extended(captivemodid->module_valid_length_hash,GINT_TO_POINTER(module->length),
                        NULL,   /* orig_key */
                        &valid_length_value_gpointer))  /* value */
-               g_hash_table_insert(module_valid_length_hash,GINT_TO_POINTER(module->length),GINT_TO_POINTER(module->cabinet_used));
+               g_hash_table_insert(captivemodid->module_valid_length_hash,
+                               GINT_TO_POINTER(module->length),GINT_TO_POINTER(module->cabinet_used));
        else {
                /* Conflicting 'cabinet_used' values for single 'cabinet size'? */
                if (valid_length_value_gpointer && GPOINTER_TO_INT(valid_length_value_gpointer)!=module->cabinet_used)
-                       g_hash_table_insert(module_valid_length_hash,GINT_TO_POINTER(module->length),NULL);
+                       g_hash_table_insert(captivemodid->module_valid_length_hash,GINT_TO_POINTER(module->length),NULL);
                }
 
        if (strcmp((const char *)module->type,"cabinet")) {
-               if (module->priority>captive_captivemodid_module_type_best_priority_lookup(module->type)) {
-                       module_type_best_priority_hash_init();
-                       g_hash_table_insert(module_type_best_priority_hash,
+               if (module->priority>captive_captivemodid_module_type_best_priority_lookup(captivemodid,module->type)) {
+                       g_hash_table_insert(captivemodid->module_type_best_priority_hash,
                                        (/* de-const */ xmlChar *)module->type,GINT_TO_POINTER(module->priority));
                        }
                }
 }
 
-gboolean captive_captivemodid_module_length_is_valid(GnomeVFSFileSize file_size)
+gboolean captive_captivemodid_module_length_is_valid(CaptiveCaptivemodidObject *captivemodid,GnomeVFSFileSize file_size)
 {
 gint file_size_gint;
 
        if ((GnomeVFSFileSize)(file_size_gint=file_size)!=file_size)    /* Size too big to be valid. */
                return FALSE;
-       module_valid_length_hash_init();
-       return g_hash_table_lookup_extended(module_valid_length_hash,GINT_TO_POINTER(file_size_gint),
+       return g_hash_table_lookup_extended(captivemodid->module_valid_length_hash,GINT_TO_POINTER(file_size_gint),
                        NULL,   /* orig_key */
                        NULL);  /* value */
 }
 
-gint captive_captivemodid_cabinet_length_to_used(gint cabinet_length)
+gint captive_captivemodid_cabinet_length_to_used(CaptiveCaptivemodidObject *captivemodid,gint cabinet_length)
 {
 gpointer valid_length_value_gpointer;
 
-       if (!g_hash_table_lookup_extended(module_valid_length_hash,GINT_TO_POINTER(cabinet_length),
+       if (!g_hash_table_lookup_extended(captivemodid->module_valid_length_hash,GINT_TO_POINTER(cabinet_length),
                        NULL,   /* orig_key */
                        &valid_length_value_gpointer))  /* value */
                return 0;
        return GPOINTER_TO_INT(valid_length_value_gpointer);
 }
 
-struct captive_captivemodid_module *captive_captivemodid_module_md5_lookup(const gchar *file_md5)
+struct captive_captivemodid_module *captive_captivemodid_module_md5_lookup
+               (CaptiveCaptivemodidObject *captivemodid,const gchar *file_md5)
 {
        g_return_val_if_fail(file_md5!=NULL,NULL);
 
-       module_md5_hash_init();
-       return g_hash_table_lookup(module_md5_hash,file_md5);
+       return g_hash_table_lookup(captivemodid->module_md5_hash,file_md5);
 }
 
-gint captive_captivemodid_module_type_best_priority_lookup(const xmlChar *module_type)
+gint captive_captivemodid_module_type_best_priority_lookup(CaptiveCaptivemodidObject *captivemodid,const xmlChar *module_type)
 {
 gpointer r_gpointer;
 gboolean errbool;
 
        g_return_val_if_fail(module_type!=NULL,G_MININT);
 
-       module_type_best_priority_hash_init();
-       errbool=g_hash_table_lookup_extended(module_type_best_priority_hash,
+       errbool=g_hash_table_lookup_extended(captivemodid->module_type_best_priority_hash,
                        module_type,    /* lookup_key */
                        NULL,   /* orig_key */
                        &r_gpointer);   /* value */
@@ -180,17 +211,17 @@ gboolean errbool;
 }
 
 /* Returns: TRUE if all modules were found. */
-gboolean captive_captivemodid_module_type_best_priority_found(const xmlChar *module_type)
+gboolean captive_captivemodid_module_type_best_priority_found
+               (CaptiveCaptivemodidObject *captivemodid,const xmlChar *module_type)
 {
 gboolean errbool;
 
        g_return_val_if_fail(module_type!=NULL,FALSE);
 
-       module_type_best_priority_hash_init();
-       errbool=g_hash_table_remove(module_type_best_priority_hash,module_type);
+       errbool=g_hash_table_remove(captivemodid->module_type_best_priority_hash,module_type);
        g_assert(errbool==TRUE);
 
-       return !g_hash_table_size(module_type_best_priority_hash);
+       return !g_hash_table_size(captivemodid->module_type_best_priority_hash);
 }
 
 static xmlChar *captive_captivemodid_load_module_xml_get_attr
@@ -229,7 +260,8 @@ char *ends;
        return r;
 }
 
-static void captive_captivemodid_load_module_xml(const gchar *captive_captivemodid_pathname,xmlTextReader *xml_reader)
+static void captive_captivemodid_load_module_xml
+               (CaptiveCaptivemodidObject *captivemodid,const gchar *captive_captivemodid_pathname,xmlTextReader *xml_reader)
 {
 struct captive_captivemodid_module *module;
 xmlChar *cabinet_used_string;
@@ -263,14 +295,11 @@ xmlChar *cabinet_used_string;
        if (G_MININT>=(module->priority=captive_captivemodid_load_module_xml_get_attr_l(captive_captivemodid_pathname,xml_reader,"priority",
                        G_MININT+1,G_MAXINT-1)))
                goto fail_free_module;
-       captive_captivemodid_load_module(module);
+       captive_captivemodid_load_module(captivemodid,module);
        return;
 
 fail_free_module:
-       xmlFree((xmlChar *)module->type);
-       xmlFree((xmlChar *)module->md5);
-       xmlFree((xmlChar *)module->id);
-       g_free(module);
+       captive_captivemodid_module_free(module);
 }
 
 static void captive_captivemodid_load_foreach
@@ -285,12 +314,19 @@ static void captive_captivemodid_load_foreach
 
 void (*captive_captivemodid_module_best_priority_notify)(const gchar *module_type);
 
-gboolean captive_captivemodid_load(const gchar *captive_captivemodid_pathname)
+CaptiveCaptivemodidObject *captive_captivemodid_load(const gchar *captive_captivemodid_pathname)
 {
+CaptiveCaptivemodidObject *captivemodid;
 xmlTextReader *xml_reader;
 
        if (!(xml_reader=xmlNewTextReaderFilename(captive_captivemodid_pathname)))
                return FALSE;
+
+       captivemodid=g_object_new(
+               CAPTIVE_CAPTIVEMODID_TYPE_OBJECT,       /* object_type */
+               NULL);  /* first_property_name; FIXME: support properties */
+       captivemodid->pathname_loaded=g_strdup(captive_captivemodid_pathname);
+
        while (1==xmlTextReaderRead(xml_reader)) {
                switch (xmlTextReaderNodeType(xml_reader)) {
 
@@ -313,7 +349,7 @@ const xmlChar *xml_name;
                                /**/ if (!xmlStrcmp(xml_name,BAD_CAST "modid")) {       /* root tag */
                                        }
                                else if (!xmlStrcmp(xml_name,BAD_CAST "module"))
-                                       captive_captivemodid_load_module_xml(captive_captivemodid_pathname,xml_reader);
+                                       captive_captivemodid_load_module_xml(captivemodid,captive_captivemodid_pathname,xml_reader);
                                else g_warning(_("%s: Unknown ELEMENT node: %s"),captive_captivemodid_pathname,xml_name);
                                xmlFree((xmlChar *)xml_name);
                                } break;
@@ -324,8 +360,59 @@ const xmlChar *xml_name;
        xmlFreeTextReader(xml_reader);
 
        if (captive_captivemodid_module_best_priority_notify) {
-               g_hash_table_foreach(module_type_best_priority_hash,
-                                               (GHFunc)captive_captivemodid_load_foreach,NULL);
+               g_hash_table_foreach(captivemodid->module_type_best_priority_hash,
+                                               (GHFunc)captive_captivemodid_load_foreach,
+                                               captivemodid);  /* user_data */
                }
-       return TRUE;
+
+       return captivemodid;
+}
+
+CaptiveCaptivemodidObject *captive_captivemodid_load_default(gboolean fatal)
+{
+CaptiveCaptivemodidObject *captivemodid=NULL;
+const gchar *pathname_default=G_STRINGIFY(SYSCONFDIR) "/w32-mod-id.captivemodid.xml";
+const gchar *msg;
+
+       if ((captivemodid=captive_captivemodid_load(pathname_default)))
+               return captivemodid;
+       if ((captivemodid=captive_captivemodid_load("./w32-mod-id.captivemodid.xml")))
+               return captivemodid;
+       msg=_("Unable to load modid database: %s");
+       if (fatal)
+               g_error(msg,pathname_default);
+       g_warning(msg,pathname_default);
+       return NULL;
+}
+
+const gchar *captive_captivemodid_get_pathname_loaded(CaptiveCaptivemodidObject *captivemodid)
+{
+       return captivemodid->pathname_loaded;
+}
+
+gchar *captive_calc_md5(gconstpointer base,size_t length)
+{
+unsigned char md5_bin[1+128/8];        /* 128 bits==16 bytes; '1+' for leading stub to prevent shorter output of BN_bn2hex() */
+BIGNUM *bignum;
+char *hex;
+gchar *r,*gs;
+
+       /* already done above */
+       /* Calculate MD5 sum and convert it to hex string: */
+       MD5(base,length,md5_bin+1);
+       md5_bin[0]=0xFF;  /* stub to prevent shorter output of BN_bn2hex() */
+       bignum=BN_bin2bn(md5_bin,1+128/8,NULL);
+       hex=BN_bn2hex(bignum);
+       g_assert(strlen(hex)==2*(1+128/8));
+       r=g_strdup(hex+2);
+       OPENSSL_free(hex);
+       BN_free(bignum);
+
+       g_assert(strlen(r)==32);
+       for (gs=r;*gs;gs++) {
+               g_assert(isxdigit(*gs));
+               *gs=tolower(*gs);
+               g_assert(isxdigit(*gs));
+               }
+       return r;
 }