+#define LOAD_IMMEDIATE(a) \
+ if (fread (&(a), sizeof (char), sizeof (a), file) != sizeof (a)) \
+ goto error
+#define LOAD_FLAG(a) \
+ do { \
+ unsigned char b; \
+ LOAD_IMMEDIATE(b); \
+ if (b > 1) \
+ goto error; \
+ (a) = b; \
+ } while (0)
+
+static int CacheLoadString (char **p, FILE *file)
+{
+ char *psz = NULL;
+ uint16_t size;
+
+ LOAD_IMMEDIATE (size);
+ if (size > 16384)
+ {
+error:
+ return -1;
+ }
+
+ if (size > 0)
+ {
+ psz = malloc (size+1);
+ if (unlikely(psz == NULL))
+ goto error;
+ if (fread (psz, 1, size, file) != size)
+ {
+ free (psz);
+ goto error;
+ }
+ psz[size] = '\0';
+ }
+ *p = psz;
+ return 0;
+}
+
+#define LOAD_STRING(a) \
+ if (CacheLoadString (&(a), file)) goto error
+
+static int CacheLoadConfig (module_config_t *cfg, FILE *file)
+{
+ LOAD_IMMEDIATE (cfg->i_type);
+ LOAD_IMMEDIATE (cfg->i_short);
+ LOAD_FLAG (cfg->b_advanced);
+ LOAD_FLAG (cfg->b_internal);
+ LOAD_FLAG (cfg->b_unsaveable);
+ LOAD_FLAG (cfg->b_safe);
+ LOAD_FLAG (cfg->b_removed);
+ LOAD_STRING (cfg->psz_type);
+ LOAD_STRING (cfg->psz_name);
+ LOAD_STRING (cfg->psz_text);
+ LOAD_STRING (cfg->psz_longtext);
+ LOAD_IMMEDIATE (cfg->list_count);
+
+ if (IsConfigStringType (cfg->i_type))
+ {
+ LOAD_STRING (cfg->orig.psz);
+ if (cfg->orig.psz != NULL)
+ cfg->value.psz = strdup (cfg->orig.psz);
+ else
+ cfg->value.psz = NULL;
+
+ if (cfg->list_count)
+ cfg->list.psz = xmalloc (cfg->list_count * sizeof (char *));
+ else /* TODO: fix config_GetPszChoices() instead of this hack: */
+ LOAD_IMMEDIATE(cfg->list.psz_cb);
+ for (unsigned i = 0; i < cfg->list_count; i++)
+ {
+ LOAD_STRING (cfg->list.psz[i]);
+ if (cfg->list.psz[i] == NULL /* NULL -> empty string */
+ && (cfg->list.psz[i] = calloc (1, 1)) == NULL)
+ goto error;
+ }
+ }
+ else
+ {
+ LOAD_IMMEDIATE (cfg->orig);
+ LOAD_IMMEDIATE (cfg->min);
+ LOAD_IMMEDIATE (cfg->max);
+ cfg->value = cfg->orig;
+
+ if (cfg->list_count)
+ cfg->list.i = xmalloc (cfg->list_count * sizeof (int));
+ else /* TODO: fix config_GetPszChoices() instead of this hack: */
+ LOAD_IMMEDIATE(cfg->list.i_cb);
+ for (unsigned i = 0; i < cfg->list_count; i++)
+ LOAD_IMMEDIATE (cfg->list.i[i]);
+ }
+ cfg->list_text = xmalloc (cfg->list_count * sizeof (char *));
+ for (unsigned i = 0; i < cfg->list_count; i++)
+ {
+ LOAD_STRING (cfg->list_text[i]);
+ if (cfg->list_text[i] == NULL /* NULL -> empty string */
+ && (cfg->list_text[i] = calloc (1, 1)) == NULL)
+ goto error;
+ }
+
+ return 0;
+error:
+ return -1; /* FIXME: leaks */
+}
+
+static int CacheLoadModuleConfig (module_t *module, FILE *file)
+{
+ uint16_t lines;
+
+ /* Calculate the structure length */
+ LOAD_IMMEDIATE (module->i_config_items);
+ LOAD_IMMEDIATE (module->i_bool_items);
+ LOAD_IMMEDIATE (lines);
+
+ /* Allocate memory */
+ if (lines)
+ {
+ module->p_config = malloc (lines * sizeof (module_config_t));
+ if (unlikely(module->p_config == NULL))
+ {
+ module->confsize = 0;
+ return -1;
+ }
+ }
+ else
+ module->p_config = NULL;
+ module->confsize = lines;
+
+ /* Do the duplication job */
+ for (size_t i = 0; i < lines; i++)
+ if (CacheLoadConfig (module->p_config + i, file))
+ return -1;
+ return 0;
+error:
+ return -1; /* FIXME: leaks */
+}
+
+