2 * W32 disk modules identifier for acquiration installation utility
3 * Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
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; exactly version 2 of June 1991 is required
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "captivemodid.h" /* self */
23 #include <glib/gmessages.h>
24 #include <libxml/xmlreader.h>
25 #include <glib/ghash.h>
28 #include <libgnomevfs/gnome-vfs-file-size.h>
29 #include <openssl/md5.h>
30 #include <openssl/bn.h>
31 #include <openssl/crypto.h>
32 #include <glib/gstrfuncs.h>
35 #include <captive/macros.h>
38 gchar *calc_md5(gconstpointer base,size_t length)
40 unsigned char md5_bin[1+128/8]; /* 128 bits==16 bytes; '1+' for leading stub to prevent shorter output of BN_bn2hex() */
45 /* already done above */
46 /* Calculate MD5 sum and convert it to hex string: */
47 MD5(base,length,md5_bin+1);
48 md5_bin[0]=0xFF; /* stub to prevent shorter output of BN_bn2hex() */
49 bignum=BN_bin2bn(md5_bin,1+128/8,NULL);
50 hex=BN_bn2hex(bignum);
51 g_assert(strlen(hex)==2*(1+128/8));
56 g_assert(strlen(r)==32);
58 g_assert(isxdigit(*gs));
60 g_assert(isxdigit(*gs));
66 /* map: GINT_TO_POINTER(captivemodid_module.length) -> !=NULL */
67 static GHashTable *module_valid_length_hash;
69 static void module_valid_length_hash_init(void)
71 if (module_valid_length_hash)
73 module_valid_length_hash=g_hash_table_new(g_direct_hash,g_direct_equal);
76 /* map: (const xmlChar *)md5 -> (struct captivemodid_module *) */
77 static GHashTable *module_md5_hash;
79 static void module_md5_hash_init(void)
83 module_md5_hash=g_hash_table_new(g_str_hash,g_str_equal);
86 static void captivemodid_load_module(struct captivemodid_module *module)
88 struct captivemodid_module *module_md5_conflict;
90 module_md5_hash_init();
91 if ((module_md5_conflict=g_hash_table_lookup(module_md5_hash,module->md5))) {
92 g_warning(_("Ignoring module \"%s\" as it has MD5 conflict with: %s"),
93 module->id,module_md5_conflict->id);
96 g_hash_table_insert(module_md5_hash,(/* de-const */ xmlChar *)module->md5,module);
97 module_valid_length_hash_init();
98 g_hash_table_insert(module_valid_length_hash,GINT_TO_POINTER(module->length),module_valid_length_hash);
101 gboolean captivemodid_module_length_is_valid(GnomeVFSFileSize file_size)
105 if ((GnomeVFSFileSize)(file_size_gint=file_size)!=file_size) /* Size too big to be valid. */
107 return !!g_hash_table_lookup(module_valid_length_hash,GINT_TO_POINTER(file_size_gint));
110 struct captivemodid_module *captivemodid_module_md5_lookup(const gchar *file_md5)
112 g_return_val_if_fail(file_md5!=NULL,NULL);
114 return g_hash_table_lookup(module_md5_hash,file_md5);
117 static xmlChar *captivemodid_load_module_xml_get_attr
118 (const gchar *captivemodid_pathname,xmlTextReader *xml_reader,const gchar *attr_name)
122 if (!(r=xmlTextReaderGetAttribute(xml_reader,attr_name))) {
123 /* FIXME: File line identification? */
124 g_warning(_("%s: Undefined attributes: %s"),captivemodid_pathname,attr_name);
130 static long captivemodid_load_module_xml_get_attr_l
131 (const gchar *captivemodid_pathname,xmlTextReader *xml_reader,const gchar *attr_name,long num_min,long num_max)
137 g_return_val_if_fail(num_min-1<num_min,-1);
138 g_return_val_if_fail(num_min<=num_max,num_min-1);
139 g_return_val_if_fail(LONG_MIN<num_min,LONG_MIN);
140 g_return_val_if_fail(num_max<LONG_MAX,num_min-1);
142 if (!(string=captivemodid_load_module_xml_get_attr(captivemodid_pathname,xml_reader,attr_name)))
144 r=strtol(string,&ends,0);
146 if (r<num_min || r>num_max) {
147 g_warning(_("%s: Numer of out range %ld..%ld: %ld"),captivemodid_pathname,num_min,num_max,r);
153 static void captivemodid_load_module_xml(const gchar *captivemodid_pathname,xmlTextReader *xml_reader)
155 struct captivemodid_module *module;
157 captive_new0(module);
158 if (!(module->type=captivemodid_load_module_xml_get_attr(captivemodid_pathname,xml_reader,"type")))
159 goto fail_free_module;
160 if (!(module->md5 =captivemodid_load_module_xml_get_attr(captivemodid_pathname,xml_reader,"md5")))
161 goto fail_free_module;
162 if (strlen(module->md5)!=strspn(module->md5,"0123456789abcdef")) {
163 g_warning(_("%s: Attribute 'md5' can be only lower-cased hexstring: %s"),captivemodid_pathname,module->md5);
164 goto fail_free_module;
166 if (strlen(module->md5)!=32) {
167 g_warning(_("%s: Attribute 'md5' length must be 32: %s"),captivemodid_pathname,module->md5);
168 goto fail_free_module;
170 if (!(module->id =captivemodid_load_module_xml_get_attr(captivemodid_pathname,xml_reader,"id")))
171 goto fail_free_module;
172 if (0>=(module->length=captivemodid_load_module_xml_get_attr_l(captivemodid_pathname,xml_reader,"length",1,G_MAXINT-1)))
173 goto fail_free_module;
174 if (G_MININT>=(module->priority=captivemodid_load_module_xml_get_attr_l(captivemodid_pathname,xml_reader,"priority",
175 G_MININT+1,G_MAXINT-1)))
176 goto fail_free_module;
177 captivemodid_load_module(module);
181 xmlFree((xmlChar *)module->type);
182 xmlFree((xmlChar *)module->md5);
183 xmlFree((xmlChar *)module->id);
188 void captivemodid_load(const gchar *captivemodid_pathname)
190 xmlTextReader *xml_reader;
192 xml_reader=xmlNewTextReaderFilename(captivemodid_pathname);
193 g_assert(xml_reader!=NULL);
194 while (1==xmlTextReaderRead(xml_reader)) {
195 switch (xmlTextReaderNodeType(xml_reader)) {
197 case XML_READER_TYPE_COMMENT:
200 case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
203 case XML_READER_TYPE_TEXT: /* Even empty nodes have some '#text'. */
206 case XML_READER_TYPE_END_ELEMENT: /* We do not track tag ends. */
209 case XML_READER_TYPE_ELEMENT: {
210 const xmlChar *xml_name;
212 xml_name=xmlTextReaderName(xml_reader);
213 /**/ if (!xmlStrcmp(xml_name,"modid")) { /* root tag */
215 else if (!xmlStrcmp(xml_name,"module"))
216 captivemodid_load_module_xml(captivemodid_pathname,xml_reader);
217 else g_warning(_("%s: Unknown ELEMENT node: %s"),captivemodid_pathname,xml_name);
218 xmlFree((xmlChar *)xml_name);
221 default: g_assert_not_reached();
224 xmlFreeTextReader(xml_reader);