From a4fb1c94ac54dbf5b425858c31d02bb2c444331a Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Fri, 25 Aug 2006 17:54:29 +0900 Subject: [PATCH] msi: Store properties in a hash table, not the database. Use string insensitive comparisons for property names. --- dlls/msi/msipriv.h | 8 +- dlls/msi/package.c | 259 ++++++++++++++++++++++++--------------------- 2 files changed, 147 insertions(+), 120 deletions(-) diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index c565b67a4ee..7c85f1c3118 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -201,6 +201,8 @@ struct tagMSIVIEW struct msi_dialog_tag; typedef struct msi_dialog_tag msi_dialog; +#define PROPERTY_HASH_SIZE 67 + typedef struct tagMSIPACKAGE { MSIOBJECTHDR hdr; @@ -218,7 +220,7 @@ typedef struct tagMSIPACKAGE struct list progids; struct list mimes; struct list appids; - + struct tagMSISCRIPT *script; struct list RunningActions; @@ -231,7 +233,9 @@ typedef struct tagMSIPACKAGE LPWSTR next_dialog; UINT WordCount; - + + struct list props[PROPERTY_HASH_SIZE]; + struct list subscriptions; } MSIPACKAGE; diff --git a/dlls/msi/package.c b/dlls/msi/package.c index d2b6f2f8ec6..13fd6cee316 100644 --- a/dlls/msi/package.c +++ b/dlls/msi/package.c @@ -49,6 +49,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); extern void msi_ui_error( DWORD msg_id, DWORD type ); +static void msi_free_properties( MSIPACKAGE *package ); + static void MSI_FreePackage( MSIOBJECTHDR *arg) { MSIPACKAGE *package= (MSIPACKAGE*) arg; @@ -57,42 +59,21 @@ static void MSI_FreePackage( MSIOBJECTHDR *arg) msi_dialog_destroy( package->dialog ); ACTION_free_package_structures(package); + msi_free_properties( package ); + msiobj_release( &package->db->hdr ); } -static UINT clone_properties(MSIDATABASE *db) +static UINT clone_properties( MSIPACKAGE *package ) { MSIQUERY * view = NULL; UINT rc; - static const WCHAR CreateSql[] = { - 'C','R','E','A','T','E',' ','T','A','B','L','E',' ','`','_','P','r','o', - 'p','e','r','t','y','`',' ','(',' ','`','_','P','r','o','p','e','r','t', - 'y','`',' ','C','H','A','R','(','5','6',')',' ','N','O','T',' ','N','U', - 'L','L',',',' ','`','V','a','l','u','e','`',' ','C','H','A','R','(','9', - '8',')',' ','N','O','T',' ','N','U','L','L',' ','P','R','I','M','A','R', - 'Y',' ','K','E','Y',' ','`','_','P','r','o','p','e','r','t','y','`',')',0}; static const WCHAR Query[] = { 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ','`','P','r','o','p','e','r','t','y','`',0}; - static const WCHAR Insert[] = { - 'I','N','S','E','R','T',' ','i','n','t','o',' ', - '`','_','P','r','o','p','e','r','t','y','`',' ', - '(','`','_','P','r','o','p','e','r','t','y','`',',', - '`','V','a','l','u','e','`',')',' ', - 'V','A','L','U','E','S',' ','(','?',',','?',')',0}; - - /* create the temporary properties table */ - rc = MSI_DatabaseOpenViewW(db, CreateSql, &view); - if (rc != ERROR_SUCCESS) - return rc; - rc = MSI_ViewExecute(view,0); - MSI_ViewClose(view); - msiobj_release(&view->hdr); - if (rc != ERROR_SUCCESS) - return rc; /* clone the existing properties */ - rc = MSI_DatabaseOpenViewW(db, Query, &view); + rc = MSI_DatabaseOpenViewW( package->db, Query, &view ); if (rc != ERROR_SUCCESS) return rc; @@ -100,31 +81,27 @@ static UINT clone_properties(MSIDATABASE *db) if (rc != ERROR_SUCCESS) { MSI_ViewClose(view); - msiobj_release(&view->hdr); + msiobj_release(&view->hdr); return rc; } while (1) { MSIRECORD * row; - MSIQUERY * view2; + LPCWSTR name, value; rc = MSI_ViewFetch(view,&row); if (rc != ERROR_SUCCESS) break; - rc = MSI_DatabaseOpenViewW(db,Insert,&view2); - if (rc!= ERROR_SUCCESS) - continue; - rc = MSI_ViewExecute(view2,row); - MSI_ViewClose(view2); - msiobj_release(&view2->hdr); - - if (rc == ERROR_SUCCESS) - msiobj_release(&row->hdr); + name = MSI_RecordGetString( row, 1 ); + value = MSI_RecordGetString( row, 2 ); + MSI_SetPropertyW( package, name, value ); + + msiobj_release( &row->hdr ); } MSI_ViewClose(view); msiobj_release(&view->hdr); - + return rc; } @@ -415,6 +392,7 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db ) 'P','r','o','d','u','c','t','C','o','d','e',0}; MSIPACKAGE *package = NULL; WCHAR uilevel[10]; + int i; TRACE("%p\n", db); @@ -447,7 +425,10 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db ) /* OK, here is where we do a slew of things to the database to * prep for all that is to come as a package */ - clone_properties(db); + for (i=0; iprops[i] ); + + clone_properties( package ); set_installer_properties(package); sprintfW(uilevel,szpi,gUILevel); MSI_SetPropertyW(package, szLevel, uilevel); @@ -847,6 +828,79 @@ out: } /* property code */ + +typedef struct msi_property { + struct list entry; + LPWSTR key; + LPWSTR value; +} msi_property; + +static UINT msi_prop_makehash( const WCHAR *str ) +{ + UINT hash = 0; + + if (str==NULL) + return hash; + + while( *str ) + { + hash ^= tolowerW( *str++ ); + hash *= 53; + hash = (hash<<5) | (hash>>27); + } + return hash % PROPERTY_HASH_SIZE; +} + +static msi_property *msi_prop_find( MSIPACKAGE *package, LPCWSTR key ) +{ + UINT hash = msi_prop_makehash( key ); + msi_property *prop; + + LIST_FOR_EACH_ENTRY( prop, &package->props[hash], msi_property, entry ) + if (!lstrcmpiW( prop->key, key )) + return prop; + return NULL; +} + +static msi_property *msi_prop_add( MSIPACKAGE *package, LPCWSTR key ) +{ + UINT hash = msi_prop_makehash( key ); + msi_property *prop; + + prop = msi_alloc( sizeof *prop ); + if (prop) + { + prop->key = strdupW( key ); + prop->value = NULL; + list_add_head( &package->props[hash], &prop->entry ); + } + return prop; +} + +static void msi_delete_property( msi_property *prop ) +{ + list_remove( &prop->entry ); + msi_free( prop->key ); + msi_free( prop->value ); + msi_free( prop ); +} + +static void msi_free_properties( MSIPACKAGE *package ) +{ + int i; + + for ( i=0; iprops[i]) ) + { + msi_property *prop; + prop = LIST_ENTRY( list_head( &package->props[i] ), + msi_property, entry ); + msi_delete_property( prop ); + } + } +} + UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue ) { LPWSTR szwName = NULL, szwValue = NULL; @@ -871,21 +925,7 @@ end: UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue) { - MSIQUERY *view; - MSIRECORD *row; - UINT rc; - DWORD sz = 0; - static const WCHAR Insert[]= - {'I','N','S','E','R','T',' ','i','n','t','o',' ','`','_','P','r','o','p' -,'e','r','t','y','`',' ','(','`','_','P','r','o','p','e','r','t','y','`' -,',','`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S' -,' ','(','?',',','?',')',0}; - static const WCHAR Update[]= - {'U','P','D','A','T','E',' ','_','P','r','o','p','e' -,'r','t','y',' ','s','e','t',' ','`','V','a','l','u','e','`',' ','=' -,' ','?',' ','w','h','e','r','e',' ','`','_','P','r','o','p' -,'e','r','t','y','`',' ','=',' ','\'','%','s','\'',0}; - WCHAR Query[1024]; + msi_property *prop; TRACE("%p %s %s\n", package, debugstr_w(szName), debugstr_w(szValue)); @@ -896,35 +936,22 @@ UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue) if (!szName[0]) return szValue ? ERROR_FUNCTION_FAILED : ERROR_SUCCESS; - rc = MSI_GetPropertyW(package,szName,0,&sz); - if (rc==ERROR_MORE_DATA || rc == ERROR_SUCCESS) + prop = msi_prop_find( package, szName ); + if (!prop) + prop = msi_prop_add( package, szName ); + + if (!prop) + return ERROR_OUTOFMEMORY; + + if (szValue) { - sprintfW(Query,Update,szName); - - row = MSI_CreateRecord(1); - MSI_RecordSetStringW(row,1,szValue); - + msi_free( prop->value ); + prop->value = strdupW( szValue ); } else - { - strcpyW(Query,Insert); + msi_delete_property( prop ); - row = MSI_CreateRecord(2); - MSI_RecordSetStringW(row,1,szName); - MSI_RecordSetStringW(row,2,szValue); - } - - rc = MSI_DatabaseOpenViewW(package->db,Query,&view); - if (rc == ERROR_SUCCESS) - { - rc = MSI_ViewExecute(view,row); - - MSI_ViewClose(view); - msiobj_release(&view->hdr); - } - msiobj_release(&row->hdr); - - return rc; + return ERROR_SUCCESS; } UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue) @@ -940,59 +967,57 @@ UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue return ret; } -static MSIRECORD *MSI_GetPropertyRow( MSIPACKAGE *package, LPCWSTR name ) -{ - static const WCHAR query[]= - {'S','E','L','E','C','T',' ','`','V','a','l','u','e','`',' ', - 'F','R','O','M',' ' ,'`','_','P','r','o','p','e','r','t','y','`', - ' ','W','H','E','R','E',' ' ,'`','_','P','r','o','p','e','r','t','y','`', - '=','\'','%','s','\'',0}; - - if (!name || !name[0]) - return NULL; - - return MSI_QueryGetRecord( package->db, query, name ); -} - /* internal function, not compatible with MsiGetPropertyW */ UINT MSI_GetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPWSTR szValueBuf, DWORD* pchValueBuf ) { - MSIRECORD *row; - UINT rc = ERROR_FUNCTION_FAILED; - - row = MSI_GetPropertyRow( package, szName ); + msi_property *prop; + UINT r, len; if (*pchValueBuf > 0) szValueBuf[0] = 0; - if (row) - { - rc = MSI_RecordGetStringW(row,1,szValueBuf,pchValueBuf); - msiobj_release(&row->hdr); - } - - if (rc == ERROR_SUCCESS) - TRACE("returning %s for property %s\n", debugstr_w(szValueBuf), - debugstr_w(szName)); - else if (rc == ERROR_MORE_DATA) - TRACE("need %li sized buffer for %s\n", *pchValueBuf, - debugstr_w(szName)); - else + prop = msi_prop_find( package, szName ); + if (!prop) { *pchValueBuf = 0; TRACE("property %s not found\n", debugstr_w(szName)); + return ERROR_FUNCTION_FAILED; } - return rc; + if (prop->value) + { + len = lstrlenW( prop->value ); + lstrcpynW(szValueBuf, prop->value, *pchValueBuf); + } + else + { + len = 1; + if( *pchValueBuf > 0 ) + szValueBuf[0] = 0; + } + + TRACE("%s -> %s\n", debugstr_w(szName), debugstr_w(szValueBuf)); + + if ( *pchValueBuf <= len ) + { + TRACE("have %lu, need %lu -> ERROR_MORE_DATA\n", *pchValueBuf, len); + r = ERROR_MORE_DATA; + } + else + r = ERROR_SUCCESS; + + *pchValueBuf = len; + + return r; } -static UINT MSI_GetProperty( MSIHANDLE handle, LPCWSTR name, +static UINT MSI_GetProperty( MSIHANDLE handle, LPCWSTR name, awstring *szValueBuf, DWORD* pchValueBuf ) { static const WCHAR empty[] = {0}; + msi_property *prop; MSIPACKAGE *package; - MSIRECORD *row = NULL; UINT r; LPCWSTR val = NULL; @@ -1006,17 +1031,15 @@ static UINT MSI_GetProperty( MSIHANDLE handle, LPCWSTR name, if (!package) return ERROR_INVALID_HANDLE; - row = MSI_GetPropertyRow( package, name ); - if (row) - val = MSI_RecordGetString( row, 1 ); + prop = msi_prop_find( package, name ); + if (prop) + val = prop->value; if (!val) val = empty; r = msi_strcpy_to_awstring( val, szValueBuf, pchValueBuf ); - if (row) - msiobj_release( &row->hdr ); msiobj_release( &package->hdr ); return r; @@ -1040,7 +1063,7 @@ UINT WINAPI MsiGetPropertyA( MSIHANDLE hInstall, LPCSTR szName, msi_free( name ); return r; } - + UINT WINAPI MsiGetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPWSTR szValueBuf, DWORD* pchValueBuf ) {