table.c

来自「一个类似windows」· C语言 代码 · 共 1,862 行 · 第 1/4 页

C
1,862
字号
        goto err;

    /* transpose all the data */
    TRACE("Transposing data from %d columns\n", t->row_count );
    for( i=0; i<t->row_count; i++ )
    {
        t->data[i] = msi_alloc( row_size );
        if( !t->data[i] )
            goto err;

        for( j=0; j<num_cols; j++ )
        {
            UINT ofs = cols[j].offset/2;
            UINT n = bytes_per_column( &cols[j] );

            switch( n )
            {
            case 2:
                t->data[i][ofs] = rawdata[ofs*t->row_count + i ];
                break;
            case 4:
                t->data[i][ofs] = rawdata[ofs*t->row_count + i*2 ];
                t->data[i][ofs+1] = rawdata[ofs*t->row_count + i*2 + 1];
                break;
            default:
                ERR("oops - unknown column width %d\n", n);
                goto err;
            }
        }
    }

    msi_free( rawdata );
    return t;
err:
    msi_free( rawdata );
    free_table( t );
    return NULL;
}

void free_cached_tables( MSIDATABASE *db )
{
    while( !list_empty( &db->tables ) )
    {
        MSITABLE *t = LIST_ENTRY( list_head( &db->tables ), MSITABLE, entry );

        list_remove( &t->entry );
        free_table( t );
    }
}

static MSITABLE *find_cached_table( MSIDATABASE *db, LPCWSTR name )
{
    MSITABLE *t;

    LIST_FOR_EACH_ENTRY( t, &db->tables, MSITABLE, entry )
        if( !lstrcmpW( name, t->name ) )
            return t;

    return NULL;
}

static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO **pcols, UINT *pcount )
{
    UINT r, column_count = 0;
    MSICOLUMNINFO *columns;

    /* get the number of columns in this table */
    column_count = 0;
    r = get_tablecolumns( db, name, NULL, &column_count );
    if( r != ERROR_SUCCESS )
        return r;

    /* if there's no columns, there's no table */
    if( column_count == 0 )
        return ERROR_INVALID_PARAMETER;

    TRACE("Table %s found\n", debugstr_w(name) );

    columns = msi_alloc( column_count*sizeof (MSICOLUMNINFO) );
    if( !columns )
        return ERROR_FUNCTION_FAILED;

    r = get_tablecolumns( db, name, columns, &column_count );
    if( r != ERROR_SUCCESS )
    {
        msi_free( columns );
        return ERROR_FUNCTION_FAILED;
    }

    *pcols = columns;
    *pcount = column_count;

    return r;
}

static MSITABLE *get_table( MSIDATABASE *db, LPCWSTR name,
                            const MSICOLUMNINFO *cols, UINT num_cols )
{
    MSITABLE *table;

    /* first, see if the table is cached */
    table = find_cached_table( db, name );
    if( table )
        return table;

    table = read_table_from_storage( db->storage, name, cols, num_cols );
    if( table )
        list_add_head( &db->tables, &table->entry );

    return table;
}

static UINT save_table( MSIDATABASE *db, MSITABLE *t )
{
    USHORT *rawdata = NULL, *p;
    UINT rawsize, r, i, j, row_size, num_cols = 0;
    MSICOLUMNINFO *cols = NULL;

    TRACE("Saving %s\n", debugstr_w( t->name ) );

    r = table_get_column_info( db, t->name, &cols, &num_cols );
    if( r != ERROR_SUCCESS )
        return r;
    
    row_size = msi_table_get_row_size( cols, num_cols );

    rawsize = t->row_count * row_size;
    rawdata = msi_alloc_zero( rawsize );
    if( !rawdata )
    {
        r = ERROR_NOT_ENOUGH_MEMORY;
        goto err;
    }

    p = rawdata;
    for( i=0; i<num_cols; i++ )
    {
        for( j=0; j<t->row_count; j++ )
        {
            UINT offset = cols[i].offset;

            *p++ = t->data[j][offset/2];
            if( 4 == bytes_per_column( &cols[i] ) )
                *p++ = t->data[j][offset/2+1];
        }
    }

    TRACE("writing %d bytes\n", rawsize);
    r = write_stream_data( db->storage, t->name, rawdata, rawsize );

err:
    msi_free_colinfo( cols, num_cols );
    msi_free( cols );
    msi_free( rawdata );

    return r;
}

HRESULT init_string_table( IStorage *stg )
{
    HRESULT r;
    static const WCHAR szStringData[] = {
        '_','S','t','r','i','n','g','D','a','t','a',0 };
    static const WCHAR szStringPool[] = {
        '_','S','t','r','i','n','g','P','o','o','l',0 };
    USHORT zero[2] = { 0, 0 };
    ULONG count = 0;
    IStream *stm = NULL;
    LPWSTR encname;

    encname = encode_streamname(TRUE, szStringPool );

    /* create the StringPool stream... add the zero string to it*/
    r = IStorage_CreateStream( stg, encname,
            STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
    msi_free( encname );
    if( r ) 
    {
        TRACE("Failed\n");
        return r;
    }

    r = IStream_Write(stm, zero, sizeof zero, &count );
    IStream_Release( stm );

    if( FAILED( r ) || ( count != sizeof zero ) )
    {
        TRACE("Failed\n");
        return E_FAIL;
    }

    /* create the StringData stream... make it zero length */
    encname = encode_streamname(TRUE, szStringData );
    r = IStorage_CreateStream( stg, encname,
            STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
    msi_free( encname );
    if( r ) 
    {
        TRACE("Failed\n");
        return E_FAIL;
    }
    IStream_Release( stm );

    return r;
}

string_table *load_string_table( IStorage *stg )
{
    string_table *st = NULL;
    CHAR *data;
    USHORT *pool;
    UINT r, datasize = 0, poolsize = 0, codepage;
    DWORD i, count, offset, len, n;
    static const WCHAR szStringData[] = {
        '_','S','t','r','i','n','g','D','a','t','a',0 };
    static const WCHAR szStringPool[] = {
        '_','S','t','r','i','n','g','P','o','o','l',0 };

    r = read_stream_data( stg, szStringPool, &pool, &poolsize );
    if( r != ERROR_SUCCESS)
        goto end;
    r = read_stream_data( stg, szStringData, (USHORT**)&data, &datasize );
    if( r != ERROR_SUCCESS)
        goto end;

    count = poolsize/4;
    if( poolsize > 4 )
        codepage = pool[0] | ( pool[1] << 16 );
    else
        codepage = CP_ACP;
    st = msi_init_stringtable( count, codepage );

    offset = 0;
    n = 1;
    for( i=1; i<count; i++ )
    {
        len = pool[i*2];

        /*
         * If a string is over 64k, the previous string entry is made null
         * and its the high word of the length is inserted in the null string's
         * reference count field.
         */
        if( pool[i*2-2] == 0 )
            len += pool[i*2-1] * 0x10000;

        if( (offset + len) > datasize )
        {
            ERR("string table corrupt?\n");
            break;
        }

        /* don't add the high word of a string's length as a string */
        if ( len || !pool[i*2+1] )
        {
            r = msi_addstring( st, n, data+offset, len, pool[i*2+1] );
            if( r != n )
                ERR("Failed to add string %ld\n", n );
            n++;
        }

        offset += len;
    }

    if ( datasize != offset )
        ERR("string table load failed! (%08x != %08lx)\n", datasize, offset );

    TRACE("Loaded %ld strings\n", count);

end:
    msi_free( pool );
    msi_free( data );

    return st;
}

static UINT save_string_table( MSIDATABASE *db )
{
    UINT i, count, datasize, poolsize, sz, used, r, codepage;
    UINT ret = ERROR_FUNCTION_FAILED;
    static const WCHAR szStringData[] = {
        '_','S','t','r','i','n','g','D','a','t','a',0 };
    static const WCHAR szStringPool[] = {
        '_','S','t','r','i','n','g','P','o','o','l',0 };
    CHAR *data = NULL;
    USHORT *pool = NULL;

    TRACE("\n");

    /* construct the new table in memory first */
    datasize = msi_string_totalsize( db->strings, &count );
    poolsize = count*2*sizeof(USHORT);

    pool = msi_alloc( poolsize );
    if( ! pool )
    {
        WARN("Failed to alloc pool %d bytes\n", poolsize );
        goto err;
    }
    data = msi_alloc( datasize );
    if( ! data )
    {
        WARN("Failed to alloc data %d bytes\n", poolsize );
        goto err;
    }

    used = 0;
    codepage = msi_string_get_codepage( db->strings );
    pool[0]=codepage&0xffff;
    pool[1]=(codepage>>16);
    for( i=1; i<count; i++ )
    {
        sz = datasize - used;
        r = msi_id2stringA( db->strings, i, data+used, &sz );
        if( r != ERROR_SUCCESS )
        {
            ERR("failed to fetch string\n");
            sz = 0;
        }
        if( sz && (sz < (datasize - used ) ) )
            sz--;
        TRACE("adding %u bytes %s\n", sz, debugstr_a(data+used) );
        pool[ i*2 ] = sz;
        pool[ i*2 + 1 ] = msi_id_refcount( db->strings, i );
        used += sz;
        if( used > datasize  )
        {
            ERR("oops overran %d >= %d\n", used, datasize);
            goto err;
        }
    }

    if( used != datasize )
    {
        ERR("oops used %d != datasize %d\n", used, datasize);
        goto err;
    }

    /* write the streams */
    r = write_stream_data( db->storage, szStringData, data, datasize );
    TRACE("Wrote StringData r=%08x\n", r);
    if( r )
        goto err;
    r = write_stream_data( db->storage, szStringPool, pool, poolsize );
    TRACE("Wrote StringPool r=%08x\n", r);
    if( r )
        goto err;

    ret = ERROR_SUCCESS;

err:
    msi_free( data );
    msi_free( pool );

    return ret;
}

/* information for default tables */
static const WCHAR szTables[]  = { '_','T','a','b','l','e','s',0 };
static const WCHAR szTable[]  = { 'T','a','b','l','e',0 };
static const WCHAR szName[]    = { 'N','a','m','e',0 };
static const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 };
static const WCHAR szColumn[]  = { 'C','o','l','u','m','n',0 };
static const WCHAR szNumber[]  = { 'N','u','m','b','e','r',0 };
static const WCHAR szType[]    = { 'T','y','p','e',0 };

static const MSICOLUMNINFO _Columns_cols[4] = {
    { szColumns, 1, szTable,  MSITYPE_VALID | MSITYPE_STRING | 64, 0 },
    { szColumns, 2, szNumber, MSITYPE_VALID | 2,                   2 },
    { szColumns, 3, szName,   MSITYPE_VALID | MSITYPE_STRING | 64, 4 },
    { szColumns, 4, szType,   MSITYPE_VALID | 2,                   6 },
};
static const MSICOLUMNINFO _Tables_cols[1] = {
    { szTables,  1, szName,   MSITYPE_VALID | MSITYPE_STRING | 64, 0 },
};

static UINT get_defaulttablecolumns( LPCWSTR name, MSICOLUMNINFO *colinfo, UINT *sz)
{
    const MSICOLUMNINFO *p;
    DWORD i, n;

    TRACE("%s\n", debugstr_w(name));

    if (!lstrcmpW( name, szTables ))
    {
        p = _Tables_cols;
        n = 1;
    }
    else if (!lstrcmpW( name, szColumns ))
    {
        p = _Columns_cols;
        n = 4;
    }
    else
        return ERROR_FUNCTION_FAILED;

    /* duplicate the string data so we can free it in msi_free_colinfo */
    for (i=0; i<n; i++)
    {
        if (colinfo && (i < *sz) )
        {
            memcpy( &colinfo[i], &p[i], sizeof(MSICOLUMNINFO) );
            colinfo[i].tablename = strdupW( p[i].tablename );
            colinfo[i].colname = strdupW( p[i].colname );
        }
        if( colinfo && (i >= *sz) )
            break;
    }
    *sz = n;
    return ERROR_SUCCESS;
}

static void msi_free_colinfo( MSICOLUMNINFO *colinfo, UINT count )
{
    UINT i;

    for( i=0; i<count; i++ )
    {
        msi_free( (LPWSTR) colinfo[i].tablename );
        msi_free( (LPWSTR) colinfo[i].colname );
    }
}

LPWSTR MSI_makestring( MSIDATABASE *db, UINT stringid)
{
    UINT sz=0, r;
    LPWSTR str;

    r = msi_id2stringW( db->strings, stringid, NULL, &sz );
    if( r != ERROR_SUCCESS )
        return NULL;
    str = msi_alloc( sz*sizeof (WCHAR) );
    if( !str )
        return str;
    r = msi_id2stringW( db->strings, stringid, str, &sz );
    if( r == ERROR_SUCCESS )
        return str;
    msi_free( str );
    return NULL;
}

static UINT get_tablecolumns( MSIDATABASE *db, 
       LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz)
{
    UINT r, i, n=0, table_id, count, maxcount = *sz;
    MSITABLE *table = NULL;

    /* first check if there is a default table with that name */
    r = get_defaulttablecolumns( szTableName, colinfo, sz );
    if( ( r == ERROR_SUCCESS ) && *sz )
        return r;

    table = get_table( db, szColumns, _Columns_cols, 4 );
    if( !table )
    {
        ERR("couldn't load _Columns table\n");
        return ERROR_FUNCTION_FAILED;
    }

    /* convert table and column names to IDs from the string table */
    r = msi_string2idW( db->strings, szTableName, &table_id );
    if( r != ERROR_SUCCESS )
    {
        WARN("Couldn't find id for %s\n", debugstr_w(szTableName));
        return r;
    }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?