Esempio n. 1
0
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 */
}
Esempio n. 2
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;
}
Esempio n. 3
0
File: cache.c Progetto: ares89/vlc
static int CacheLoadConfig (module_config_t *cfg, FILE *file)
{
    LOAD_IMMEDIATE (cfg->flags);
    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 */
}
Esempio n. 4
0
/**
 * Loads a plugins cache file.
 *
 * This function will load the plugin cache if present and valid. This cache
 * will in turn be queried by AllocateAllPlugins() to see if it needs to
 * actually load the dynamically loadable module.
 * This allows us to only fully load plugins when they are actually used.
 */
size_t CacheLoad( vlc_object_t *p_this, const char *dir, module_cache_t **r )
{
    char *psz_filename;
    FILE *file;
    int i_size, i_read;
    char p_cachestring[sizeof(CACHE_STRING)];
    size_t i_cache;
    int32_t i_marker;

    assert( dir != NULL );

    *r = NULL;
    if( asprintf( &psz_filename, "%s"DIR_SEP CACHE_NAME, dir ) == -1 )
        return 0;

    msg_Dbg( p_this, "loading plugins cache file %s", psz_filename );

    file = vlc_fopen( psz_filename, "rb" );
    if( !file )
    {
        msg_Warn( p_this, "cannot read %s: %s", psz_filename,
                  vlc_strerror_c(errno) );
        free( psz_filename );
        return 0;
    }
    free( psz_filename );

    /* Check the file is a plugins cache */
    i_size = sizeof(CACHE_STRING) - 1;
    i_read = fread( p_cachestring, 1, i_size, file );
    if( i_read != i_size ||
        memcmp( p_cachestring, CACHE_STRING, i_size ) )
    {
        msg_Warn( p_this, "This doesn't look like a valid plugins cache" );
        fclose( file );
        return 0;
    }

#ifdef DISTRO_VERSION
    /* Check for distribution specific version */
    char p_distrostring[sizeof( DISTRO_VERSION )];
    i_size = sizeof( DISTRO_VERSION ) - 1;
    i_read = fread( p_distrostring, 1, i_size, file );
    if( i_read != i_size ||
        memcmp( p_distrostring, DISTRO_VERSION, i_size ) )
    {
        msg_Warn( p_this, "This doesn't look like a valid plugins cache" );
        fclose( file );
        return 0;
    }
#endif

    /* Check Sub-version number */
    i_read = fread( &i_marker, 1, sizeof(i_marker), file );
    if( i_read != sizeof(i_marker) || i_marker != CACHE_SUBVERSION_NUM )
    {
        msg_Warn( p_this, "This doesn't look like a valid plugins cache "
                  "(corrupted header)" );
        fclose( file );
        return 0;
    }

    /* Check header marker */
    i_read = fread( &i_marker, 1, sizeof(i_marker), file );
    if( i_read != sizeof(i_marker) ||
        i_marker != ftell( file ) - (int)sizeof(i_marker) )
    {
        msg_Warn( p_this, "This doesn't look like a valid plugins cache "
                  "(corrupted header)" );
        fclose( file );
        return 0;
    }

    if (fread( &i_cache, 1, sizeof(i_cache), file ) != sizeof(i_cache) )
    {
        msg_Warn( p_this, "This doesn't look like a valid plugins cache "
                  "(file too short)" );
        fclose( file );
        return 0;
    }

    module_cache_t *cache = NULL;

    for (size_t count = 0; count < i_cache;)
    {
        module_t *module;
        int i_submodules;

        module = vlc_module_create (NULL);

        /* Load additional infos */
        LOAD_STRING(module->psz_shortname);
        LOAD_STRING(module->psz_longname);
        LOAD_STRING(module->psz_help);

        LOAD_IMMEDIATE(module->i_shortcuts);
        if (module->i_shortcuts > MODULE_SHORTCUT_MAX)
            goto error;
        else
        {
            module->pp_shortcuts =
                              xmalloc (sizeof (*module->pp_shortcuts) * module->i_shortcuts);
            for (unsigned j = 0; j < module->i_shortcuts; j++)
                LOAD_STRING(module->pp_shortcuts[j]);
        }

        LOAD_STRING(module->psz_capability);
        LOAD_IMMEDIATE(module->i_score);
        LOAD_IMMEDIATE(module->b_unloadable);

        /* Config stuff */
        if (CacheLoadModuleConfig (module, file) != VLC_SUCCESS)
            goto error;

        LOAD_STRING(module->domain);
        if (module->domain != NULL)
            vlc_bindtextdomain (module->domain);

        LOAD_IMMEDIATE( i_submodules );

        while( i_submodules-- )
        {
            module_t *submodule = vlc_module_create (module);
            free (submodule->pp_shortcuts);
            LOAD_STRING(submodule->psz_shortname);
            LOAD_STRING(submodule->psz_longname);

            LOAD_IMMEDIATE(submodule->i_shortcuts);
            if (submodule->i_shortcuts > MODULE_SHORTCUT_MAX)
                goto error;
            else
            {
                submodule->pp_shortcuts =
                           xmalloc (sizeof (*submodule->pp_shortcuts) * submodule->i_shortcuts);
                for (unsigned j = 0; j < submodule->i_shortcuts; j++)
                    LOAD_STRING(submodule->pp_shortcuts[j]);
            }

            LOAD_STRING(submodule->psz_capability);
            LOAD_IMMEDIATE(submodule->i_score);
        }

        char *path;
        struct stat st;

        /* Load common info */
        LOAD_STRING(path);
        if (path == NULL)
            goto error;
        LOAD_IMMEDIATE(st.st_mtime);
        LOAD_IMMEDIATE(st.st_size);

        CacheAdd (&cache, &count, path, &st, module);
        free (path);
        /* TODO: deal with errors */
    }
    fclose( file );

    *r = cache;
    return i_cache;

error:
    msg_Warn( p_this, "plugins cache not loaded (corrupted)" );

    /* TODO: cleanup */
    fclose( file );
    return 0;
}
Esempio n. 5
0
static int CacheLoadConfig( module_t *p_module, FILE *file )
{
    uint32_t i_lines;
    uint16_t i_size;

    /* Calculate the structure length */
    LOAD_IMMEDIATE( p_module->i_config_items );
    LOAD_IMMEDIATE( p_module->i_bool_items );

    LOAD_IMMEDIATE( i_lines );

    /* Allocate memory */
    if (i_lines)
    {
        p_module->p_config =
            (module_config_t *)calloc( i_lines, sizeof(module_config_t) );
        if( p_module->p_config == NULL )
        {
            p_module->confsize = 0;
            return VLC_ENOMEM;
        }
    }
    p_module->confsize = i_lines;

    /* Do the duplication job */
    for (size_t i = 0; i < i_lines; i++ )
    {
        LOAD_IMMEDIATE( p_module->p_config[i] );

        LOAD_STRING( p_module->p_config[i].psz_type );
        LOAD_STRING( p_module->p_config[i].psz_name );
        LOAD_STRING( p_module->p_config[i].psz_text );
        LOAD_STRING( p_module->p_config[i].psz_longtext );

        if (IsConfigStringType (p_module->p_config[i].i_type))
        {
            LOAD_STRING (p_module->p_config[i].orig.psz);
            p_module->p_config[i].value.psz =
                    (p_module->p_config[i].orig.psz != NULL)
                        ? strdup (p_module->p_config[i].orig.psz) : NULL;
        }
        else
            memcpy (&p_module->p_config[i].value, &p_module->p_config[i].orig,
                    sizeof (p_module->p_config[i].value));

        p_module->p_config[i].b_dirty = false;

        if( p_module->p_config[i].i_list )
        {
            if( p_module->p_config[i].ppsz_list )
            {
                int j;
                p_module->p_config[i].ppsz_list =
                    xmalloc( (p_module->p_config[i].i_list+1) * sizeof(char *));
                if( p_module->p_config[i].ppsz_list )
                {
                    for( j = 0; j < p_module->p_config[i].i_list; j++ )
                        LOAD_STRING( p_module->p_config[i].ppsz_list[j] );
                    p_module->p_config[i].ppsz_list[j] = NULL;
                }
            }
            if( p_module->p_config[i].ppsz_list_text )
            {
                int j;
                p_module->p_config[i].ppsz_list_text =
                    xmalloc( (p_module->p_config[i].i_list+1) * sizeof(char *));
                if( p_module->p_config[i].ppsz_list_text )
                {
                  for( j = 0; j < p_module->p_config[i].i_list; j++ )
                      LOAD_STRING( p_module->p_config[i].ppsz_list_text[j] );
                  p_module->p_config[i].ppsz_list_text[j] = NULL;
                }
            }
            if( p_module->p_config[i].pi_list )
            {
                p_module->p_config[i].pi_list =
                    xmalloc( (p_module->p_config[i].i_list + 1) * sizeof(int) );
                if( p_module->p_config[i].pi_list )
                {
                    for (int j = 0; j < p_module->p_config[i].i_list; j++)
                        LOAD_IMMEDIATE( p_module->p_config[i].pi_list[j] );
                }
            }
        }

        if( p_module->p_config[i].i_action )
        {
            p_module->p_config[i].ppf_action =
                xmalloc( p_module->p_config[i].i_action * sizeof(void *) );
            p_module->p_config[i].ppsz_action_text =
                xmalloc( p_module->p_config[i].i_action * sizeof(char *) );

            for (int j = 0; j < p_module->p_config[i].i_action; j++)
            {
                p_module->p_config[i].ppf_action[j] = NULL;
                LOAD_STRING( p_module->p_config[i].ppsz_action_text[j] );
            }
        }
    }

    return VLC_SUCCESS;

 error:

    return VLC_EGENERIC;
}
Esempio n. 6
0
/**
 * Loads a plugins cache file.
 *
 * This function will load the plugin cache if present and valid. This cache
 * will in turn be queried by AllocateAllPlugins() to see if it needs to
 * actually load the dynamically loadable module.
 * This allows us to only fully load plugins when they are actually used.
 */
size_t CacheLoad( vlc_object_t *p_this, const char *dir, module_cache_t ***r )
{
    char *psz_filename;
    FILE *file;
    int i_size, i_read;
    char p_cachestring[sizeof(CACHE_STRING)];
    size_t i_cache;
    int32_t i_file_size, i_marker;

    assert( dir != NULL );

    *r = NULL;
    if( asprintf( &psz_filename, "%s"DIR_SEP CACHE_NAME, dir ) == -1 )
        return 0;

    msg_Dbg( p_this, "loading plugins cache file %s", psz_filename );

    file = vlc_fopen( psz_filename, "rb" );
    if( !file )
    {
        msg_Warn( p_this, "cannot read %s (%m)",
                  psz_filename );
        free( psz_filename );
        return 0;
    }
    free( psz_filename );

    /* Check the file size */
    i_read = fread( &i_file_size, 1, sizeof(i_file_size), file );
    if( i_read != sizeof(i_file_size) )
    {
        msg_Warn( p_this, "This doesn't look like a valid plugins cache "
                  "(too short)" );
        fclose( file );
        return 0;
    }

    fseek( file, 0, SEEK_END );
    if( ftell( file ) != i_file_size )
    {
        msg_Warn( p_this, "This doesn't look like a valid plugins cache "
                  "(corrupted size)" );
        fclose( file );
        return 0;
    }
    fseek( file, sizeof(i_file_size), SEEK_SET );

    /* Check the file is a plugins cache */
    i_size = sizeof(CACHE_STRING) - 1;
    i_read = fread( p_cachestring, 1, i_size, file );
    if( i_read != i_size ||
        memcmp( p_cachestring, CACHE_STRING, i_size ) )
    {
        msg_Warn( p_this, "This doesn't look like a valid plugins cache" );
        fclose( file );
        return 0;
    }

#ifdef DISTRO_VERSION
    /* Check for distribution specific version */
    char p_distrostring[sizeof( DISTRO_VERSION )];
    i_size = sizeof( DISTRO_VERSION ) - 1;
    i_read = fread( p_distrostring, 1, i_size, file );
    if( i_read != i_size ||
        memcmp( p_distrostring, DISTRO_VERSION, i_size ) )
    {
        msg_Warn( p_this, "This doesn't look like a valid plugins cache" );
        fclose( file );
        return 0;
    }
#endif

    /* Check Sub-version number */
    i_read = fread( &i_marker, 1, sizeof(i_marker), file );
    if( i_read != sizeof(i_marker) || i_marker != CACHE_SUBVERSION_NUM )
    {
        msg_Warn( p_this, "This doesn't look like a valid plugins cache "
                  "(corrupted header)" );
        fclose( file );
        return 0;
    }

    /* Check header marker */
    i_read = fread( &i_marker, 1, sizeof(i_marker), file );
    if( i_read != sizeof(i_marker) ||
        i_marker != ftell( file ) - (int)sizeof(i_marker) )
    {
        msg_Warn( p_this, "This doesn't look like a valid plugins cache "
                  "(corrupted header)" );
        fclose( file );
        return 0;
    }

    if (fread( &i_cache, 1, sizeof(i_cache), file ) != sizeof(i_cache) )
    {
        msg_Warn( p_this, "This doesn't look like a valid plugins cache "
                  "(file too short)" );
        fclose( file );
        return 0;
    }

    module_cache_t **pp_cache = malloc( i_cache * sizeof(*pp_cache) );
    if( pp_cache == NULL )
        i_cache = 0; /* don't load anything */

#define LOAD_IMMEDIATE(a) \
    if( fread( (void *)&a, sizeof(char), sizeof(a), file ) != sizeof(a) ) goto error
#define LOAD_STRING(a) \
{ \
    a = NULL; \
    if( ( fread( &i_size, sizeof(i_size), 1, file ) != 1 ) \
     || ( i_size > 16384 ) ) \
        goto error; \
    if( i_size ) { \
        char *psz = xmalloc( i_size ); \
        if( fread( psz, i_size, 1, file ) != 1 ) { \
            free( psz ); \
            goto error; \
        } \
        if( psz[i_size-1] ) { \
            free( psz ); \
            goto error; \
        } \
        a = psz; \
    } \
}

    for( size_t i = 0; i < i_cache; i++ )
    {
        uint16_t i_size;
        int i_submodules;

        pp_cache[i] = xmalloc( sizeof(module_cache_t) );

        /* Load common info */
        LOAD_STRING( pp_cache[i]->path );
        LOAD_IMMEDIATE( pp_cache[i]->mtime );
        LOAD_IMMEDIATE( pp_cache[i]->size );

        pp_cache[i]->p_module = vlc_module_create();

        /* Load additional infos */
        free( pp_cache[i]->p_module->psz_object_name );
        LOAD_STRING( pp_cache[i]->p_module->psz_object_name );
        LOAD_STRING( pp_cache[i]->p_module->psz_shortname );
        LOAD_STRING( pp_cache[i]->p_module->psz_longname );
        LOAD_STRING( pp_cache[i]->p_module->psz_help );

        LOAD_IMMEDIATE( pp_cache[i]->p_module->i_shortcuts );
        if( pp_cache[i]->p_module->i_shortcuts > MODULE_SHORTCUT_MAX )
            goto error;
        else if( pp_cache[i]->p_module->i_shortcuts == 0 )
            pp_cache[i]->p_module->pp_shortcuts = NULL;
        else
        {
            pp_cache[i]->p_module->pp_shortcuts =
                    xmalloc( sizeof( char ** ) * pp_cache[i]->p_module->i_shortcuts );
            for( unsigned j = 0; j < pp_cache[i]->p_module->i_shortcuts; j++ )
                LOAD_STRING( pp_cache[i]->p_module->pp_shortcuts[j] );
        }

        LOAD_STRING( pp_cache[i]->p_module->psz_capability );
        LOAD_IMMEDIATE( pp_cache[i]->p_module->i_score );
        LOAD_IMMEDIATE( pp_cache[i]->p_module->b_unloadable );

        /* Config stuff */
        if( CacheLoadConfig( pp_cache[i]->p_module, file ) != VLC_SUCCESS )
            goto error;

        LOAD_STRING( pp_cache[i]->p_module->psz_filename );
        LOAD_STRING( pp_cache[i]->p_module->domain );
        if( pp_cache[i]->p_module->domain != NULL )
            vlc_bindtextdomain( pp_cache[i]->p_module->domain );

        LOAD_IMMEDIATE( i_submodules );

        while( i_submodules-- )
        {
            module_t *p_module = vlc_submodule_create( pp_cache[i]->p_module );
            free( p_module->psz_object_name );
            free( p_module->pp_shortcuts );
            LOAD_STRING( p_module->psz_object_name );
            LOAD_STRING( p_module->psz_shortname );
            LOAD_STRING( p_module->psz_longname );
            LOAD_STRING( p_module->psz_help );

            LOAD_IMMEDIATE( p_module->i_shortcuts );
            if( p_module->i_shortcuts > MODULE_SHORTCUT_MAX )
                goto error;
            else if( p_module->i_shortcuts == 0 )
                p_module->pp_shortcuts = NULL;
            else
            {
                p_module->pp_shortcuts = xmalloc( sizeof( char ** ) * p_module->i_shortcuts );
                for( unsigned j = 0; j < p_module->i_shortcuts; j++ )
                    LOAD_STRING( p_module->pp_shortcuts[j] );
            }

            LOAD_STRING( p_module->psz_capability );
            LOAD_IMMEDIATE( p_module->i_score );
            LOAD_IMMEDIATE( p_module->b_unloadable );
            LOAD_STRING( p_module->domain );
        }
    }
    fclose( file );

    *r = pp_cache;
    return i_cache;

 error:

    msg_Warn( p_this, "plugins cache not loaded (corrupted)" );

    /* TODO: cleanup */
    fclose( file );
    return 0;
}
Esempio n. 7
0
File: cache.c Progetto: 0xheart0/vlc
/**
 * Loads a plugins cache file.
 *
 * This function will load the plugin cache if present and valid. This cache
 * will in turn be queried by AllocateAllPlugins() to see if it needs to
 * actually load the dynamically loadable module.
 * This allows us to only fully load plugins when they are actually used.
 */
size_t CacheLoad( vlc_object_t *p_this, const char *dir, module_cache_t **r )
{
    char *psz_filename;
    FILE *file;
    int i_size, i_read;
    char p_cachestring[sizeof(CACHE_STRING)];
    int32_t i_marker;

    assert( dir != NULL );

    *r = NULL;
    if( asprintf( &psz_filename, "%s"DIR_SEP CACHE_NAME, dir ) == -1 )
        return 0;

    msg_Dbg( p_this, "loading plugins cache file %s", psz_filename );

    file = vlc_fopen( psz_filename, "rb" );
    if( !file )
    {
        msg_Warn( p_this, "cannot read %s: %s", psz_filename,
                  vlc_strerror_c(errno) );
        free( psz_filename );
        return 0;
    }
    free( psz_filename );

    /* Check the file is a plugins cache */
    i_size = sizeof(CACHE_STRING) - 1;
    i_read = fread( p_cachestring, 1, i_size, file );
    if( i_read != i_size ||
        memcmp( p_cachestring, CACHE_STRING, i_size ) )
    {
        msg_Warn( p_this, "This doesn't look like a valid plugins cache" );
        fclose( file );
        return 0;
    }

#ifdef DISTRO_VERSION
    /* Check for distribution specific version */
    char p_distrostring[sizeof( DISTRO_VERSION )];
    i_size = sizeof( DISTRO_VERSION ) - 1;
    i_read = fread( p_distrostring, 1, i_size, file );
    if( i_read != i_size ||
        memcmp( p_distrostring, DISTRO_VERSION, i_size ) )
    {
        msg_Warn( p_this, "This doesn't look like a valid plugins cache" );
        fclose( file );
        return 0;
    }
#endif

    /* Check sub-version number */
    i_read = fread( &i_marker, 1, sizeof(i_marker), file );
    if( i_read != sizeof(i_marker) || i_marker != CACHE_SUBVERSION_NUM )
    {
        msg_Warn( p_this, "This doesn't look like a valid plugins cache "
                  "(corrupted header)" );
        fclose( file );
        return 0;
    }

    /* Check header marker */
    i_read = fread( &i_marker, 1, sizeof(i_marker), file );
    if( i_read != sizeof(i_marker) ||
        i_marker != ftell( file ) - (int)sizeof(i_marker) )
    {
        msg_Warn( p_this, "This doesn't look like a valid plugins cache "
                  "(corrupted header)" );
        fclose( file );
        return 0;
    }

    module_cache_t *cache = NULL;
    size_t count = 0;
    char *path = NULL;

    for (;;)
    {
        module_t *module = CacheLoadModule (file);
        if (module == NULL)
        {
            if (feof (file))
                break;
            goto error;
        }

        struct stat st;

        /* Load common info */
        LOAD_STRING(path);
        if (path == NULL)
            goto error;
        LOAD_IMMEDIATE(st.st_mtime);
        LOAD_IMMEDIATE(st.st_size);

        CacheAdd (&cache, &count, path, &st, module);
        free (path);
        path = NULL;
        /* TODO: deal with errors */
    }

    fclose( file );

    *r = cache;
    return count;

error:
    free( path );
    if (ferror (file))
        msg_Err(p_this, "plugins cache read error: %s", vlc_strerror_c(errno));
    msg_Warn( p_this, "plugins cache not loaded (corrupted)" );

    /* TODO: cleanup */
    fclose( file );
    return 0;
}
Esempio n. 8
0
File: cache.c Progetto: 0xheart0/vlc
static module_t *CacheLoadModule (FILE *file)
{
    module_t *module = vlc_module_create (NULL);
    if (unlikely(module == NULL))
        return NULL;

    /* Load additional infos */
    LOAD_STRING(module->psz_shortname);
    LOAD_STRING(module->psz_longname);
    LOAD_STRING(module->psz_help);

    LOAD_IMMEDIATE(module->i_shortcuts);
    if (module->i_shortcuts > MODULE_SHORTCUT_MAX)
        goto error;
    else
    {
        module->pp_shortcuts =
            xmalloc (sizeof (*module->pp_shortcuts) * module->i_shortcuts);
        for (unsigned j = 0; j < module->i_shortcuts; j++)
            LOAD_STRING(module->pp_shortcuts[j]);
    }

    LOAD_STRING(module->psz_capability);
    LOAD_IMMEDIATE(module->i_score);
    LOAD_IMMEDIATE(module->b_unloadable);

    /* Config stuff */
    if (CacheLoadModuleConfig (module, file) != VLC_SUCCESS)
        goto error;

    LOAD_STRING(module->domain);
    if (module->domain != NULL)
        vlc_bindtextdomain (module->domain);

    uint32_t submodules;
    LOAD_IMMEDIATE(submodules);

    for (; submodules > 0; submodules--)
    {
        module_t *submodule = vlc_module_create (module);

        free (submodule->pp_shortcuts);
        LOAD_STRING(submodule->psz_shortname);
        LOAD_STRING(submodule->psz_longname);

        LOAD_IMMEDIATE(submodule->i_shortcuts);
        if (submodule->i_shortcuts > MODULE_SHORTCUT_MAX)
            goto error;
        else
        {
            submodule->pp_shortcuts =
                xmalloc (sizeof (*submodule->pp_shortcuts) * submodule->i_shortcuts);
            for (unsigned j = 0; j < submodule->i_shortcuts; j++)
                LOAD_STRING(submodule->pp_shortcuts[j]);
        }

        LOAD_STRING(submodule->psz_capability);
        LOAD_IMMEDIATE(submodule->i_score);
    }

    return module;
error:
    vlc_module_destroy(module);
    return NULL;
}