msi: format.c rewrite

Aric Stewart aric at codeweavers.com
Sun Jan 30 20:59:23 CST 2005


A reworking of format.c to remove the recursion, clean things up and 
stablize behavior to match windows.
-------------- next part --------------
Index: dlls/msi/format.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/format.c,v
retrieving revision 1.2
diff -u -u -r1.2 format.c
--- dlls/msi/format.c	26 Jan 2005 21:09:05 -0000	1.2
+++ dlls/msi/format.c	31 Jan 2005 02:58:37 -0000
@@ -49,6 +49,27 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
+
+LPWSTR build_default_format(MSIRECORD* record)
+{
+    int i;  
+    int count;
+    LPWSTR rc;
+    static const WCHAR fmt[] = {'%','i',':',' ','[','%','i',']',' ',0};
+    WCHAR buf[11];
+
+    count = MSI_RecordGetFieldCount(record);
+
+    rc = HeapAlloc(GetProcessHeap(),0,(11*count)*sizeof(WCHAR));
+    rc[0] = 0;
+    for (i = 1; i <= count; i++)
+    {
+        sprintfW(buf,fmt,i,i); 
+        strcatW(rc,buf);
+    }
+    return rc;
+}
+
 static const WCHAR* scanW(LPCWSTR buf, WCHAR token, DWORD len)
 {
     DWORD i;
@@ -58,11 +79,140 @@
     return NULL;
 }
 
+
+/* break out helper functions for deformating */
+static LPWSTR deformat_component(MSIPACKAGE* package, LPCWSTR key, DWORD* sz)
+{
+    LPWSTR value = NULL;
+    INT index;
+
+    *sz = 0;
+    if (!package)
+        return NULL;
+
+    ERR("POORLY HANDLED DEFORMAT.. [$componentkey] \n");
+    index = get_loaded_component(package,key);
+    if (index >= 0)
+    {
+        value = resolve_folder(package, package->components[index].Directory, 
+                                       FALSE, FALSE, NULL);
+        *sz = (strlenW(value)) * sizeof(WCHAR);
+    }
+
+    return value;
+}
+
+static LPWSTR deformat_file(MSIPACKAGE* package, LPCWSTR key, DWORD* sz)
+{
+    LPWSTR value = NULL;
+    INT index;
+
+    *sz = 0;
+
+    if (!package)
+        return NULL;
+
+    index = get_loaded_file(package,key);
+    if (index >=0)
+    {
+        value = dupstrW(package->files[index].TargetPath);
+        *sz = (strlenW(value)) * sizeof(WCHAR);
+    }
+
+    return value;
+}
+
+static LPWSTR deformat_environment(MSIPACKAGE* package, LPCWSTR key, 
+                                   DWORD* chunk)
+{
+    LPWSTR value = NULL;
+    DWORD sz;
+
+    sz  = GetEnvironmentVariableW(key,NULL,0);
+    if (sz > 0)
+    {
+        sz++;
+        value = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR));
+        GetEnvironmentVariableW(&key[1],value,sz);
+        *chunk = (strlenW(value)) * sizeof(WCHAR);
+    }
+    else
+    {
+        ERR("Unknown environment variable\n");
+        *chunk = 0;
+        value = NULL;
+    }
+    return value;
+}
+
+ 
+static LPWSTR deformat_NULL(DWORD* chunk)
+{
+    LPWSTR value;
+
+    value = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*2);
+    value[0] =  0;
+    *chunk = sizeof(WCHAR);
+    return value;
+}
+
+static LPWSTR deformat_escape(LPCWSTR key, DWORD* chunk)
+{
+    LPWSTR value;
+
+    value = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*2);
+    value[0] =  key[0];
+    *chunk = sizeof(WCHAR);
+
+    return value;
+}
+
+
+static BOOL is_key_number(LPCWSTR key)
+{
+    INT index = 0;
+    while (isdigitW(key[index])) index++;
+    if (key[index] == 0)
+        return TRUE;
+    else
+        return FALSE;
+}
+
+static LPWSTR deformat_index(MSIRECORD* record, LPCWSTR key, DWORD* chunk )
+{
+    INT index;
+    LPWSTR value; 
+
+    index = atoiW(key);
+    TRACE("record index %i\n",index);
+    value = load_dynamic_stringW(record,index);
+    if (value)
+        *chunk = strlenW(value) * sizeof(WCHAR);
+    else
+    {
+        value = NULL;
+        *chunk = 0;
+    }
+    return value;
+}
+
+static LPWSTR deformat_property(MSIPACKAGE* package, LPCWSTR key, DWORD* chunk)
+{
+    UINT rc;
+    LPWSTR value;
+
+    if (!package)
+        return NULL;
+
+    value = load_dynamic_property(package,key, &rc);
+
+    if (rc == ERROR_SUCCESS)
+        *chunk = (strlenW(value)) * sizeof(WCHAR);
+
+    return value;
+}
+
 /*
- * This helper function should probably go a lot of places
- *
- * Thinking about this, maybe this should become yet another Bison file
- *
  * len is in WCHARs
  * return is also in WCHARs
  */
@@ -76,9 +226,8 @@
     WCHAR key[0x100];
     LPWSTR value = NULL;
     DWORD sz;
-    UINT rc;
-    INT index;
-    LPWSTR newdata = NULL;
+    LPBYTE newdata = NULL;
+    const WCHAR* progress = NULL;
 
     if (ptr==NULL)
     {
@@ -89,7 +238,7 @@
 
     TRACE("Starting with %s\n",debugstr_w(ptr));
 
-    /* scan for special characters */
+    /* scan for special characters... fast exit */
     if (!scanW(ptr,'[',len) || (scanW(ptr,'[',len) && !scanW(ptr,']',len)))
     {
         /* not formatted */
@@ -98,154 +247,125 @@
         TRACE("Returning %s\n",debugstr_w(*data));
         return len;
     }
-   
-    /* formatted string located */ 
-    mark = scanW(ptr,'[',len);
-    if (mark != ptr)
-    {
-        INT cnt = (mark - ptr);
-        TRACE("%i  (%i) characters before marker\n",cnt,(mark-ptr));
-        size = cnt * sizeof(WCHAR);
-        newdata = HeapAlloc(GetProcessHeap(),0,size);
-        memcpy(newdata,ptr,(cnt * sizeof(WCHAR)));
-    }
-    else
-    {
-        size = 0;
-        newdata = HeapAlloc(GetProcessHeap(),0,size);
-        newdata[0]=0;
-    }
-    mark++;
-    /* there should be no null characters in a key so strchrW is ok */
-    mark2 = strchrW(mark,']');
-    strncpyW(key,mark,mark2-mark);
-    key[mark2-mark] = 0;
-    mark = strchrW(mark,']');
-    mark++;
-    TRACE("Current %s .. %s\n",debugstr_w(newdata),debugstr_w(key));
-    sz = 0;
-    /* expand what we can deformat... Again, this should become a bison file */
-    switch (key[0])
-    {
-        case '~':
-            value = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*2);
-            value[0] =  0;
-            chunk = sizeof(WCHAR);
-            rc = ERROR_SUCCESS;
-            break;
-        case '$':
-            ERR("POORLY HANDLED DEFORMAT.. [$componentkey] \n");
-            index = get_loaded_component(package,&key[1]);
-            if (index >= 0)
-            {
-                value = resolve_folder(package, 
-                                       package->components[index].Directory, 
-                                       FALSE, FALSE, NULL);
-                chunk = (strlenW(value)) * sizeof(WCHAR);
-                rc = 0;
-            }
+  
+    progress = ptr;
+
+    while (progress - ptr < len)
+    { 
+        /* formatted string located */ 
+        mark = scanW(progress,'[',len - (progress-ptr));
+        if (!mark)
+        {
+            TRACE("after value %s .. %s\n",debugstr_w((LPWSTR)newdata),
+                                       debugstr_w(mark));
+            LPBYTE nd2;
+            chunk = (len - (progress - ptr)) * sizeof(WCHAR);
+            TRACE("after chunk is %li\n",chunk);
+            if (size)
+                nd2 = HeapReAlloc(GetProcessHeap(),0,newdata,(size+chunk));
             else
-                rc = ERROR_FUNCTION_FAILED;
+                nd2 = HeapAlloc(GetProcessHeap(),0,size);
+
+            newdata = nd2;
+            memcpy(&newdata[size],progress,chunk);
+            size+=chunk;
             break;
-        case '#':
-        case '!': /* should be short path */
-            index = get_loaded_file(package,&key[1]);
-            if (index >=0)
-            {
-                sz = strlenW(package->files[index].TargetPath);
-                value = dupstrW(package->files[index].TargetPath);
-                chunk = (strlenW(value)) * sizeof(WCHAR);
-                rc= ERROR_SUCCESS;
-            }
+        }
+
+        if (mark != progress)
+        {
+            LPBYTE tgt;
+            DWORD old_size = size;
+            INT cnt = (mark - progress);
+            TRACE("%i  (%i) characters before marker\n",cnt,(mark-progress));
+            size += cnt * sizeof(WCHAR);
+            if (!old_size)
+                tgt = HeapAlloc(GetProcessHeap(),0,size);
             else
-                rc = ERROR_FUNCTION_FAILED;
-            break;
-        case '\\':
-            value = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*2);
-            value[0] =  key[1];
-            chunk = sizeof(WCHAR);
-            rc = ERROR_SUCCESS;
-            break;
-        case '%':
-            sz  = GetEnvironmentVariableW(&key[1],NULL,0);
-            if (sz > 0)
-            {
-                sz++;
-                value = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR));
-                GetEnvironmentVariableW(&key[1],value,sz);
-                chunk = (strlenW(value)) * sizeof(WCHAR);
-                rc = ERROR_SUCCESS;
-            }
+                tgt = HeapReAlloc(GetProcessHeap(),0,newdata,size);
+            newdata  = tgt;
+            memcpy(&newdata[old_size],progress,(cnt * sizeof(WCHAR)));  
+        }
+
+        progress = mark;
+
+        mark++;
+        /* there should be no null characters in a key so strchrW is ok */
+        mark2 = strchrW(mark,']');
+        strncpyW(key,mark,mark2-mark);
+        key[mark2-mark] = 0;
+        mark = strchrW(mark,']');
+        mark++;
+        TRACE("Current %s .. %s\n",debugstr_w((LPWSTR)newdata),debugstr_w(key));
+
+        if (!package)
+        {
+            /* only deformat number indexs */
+            if (is_key_number(key))
+                value = deformat_index(record,key,&chunk);  
             else
             {
-                ERR("Unknown environment variable\n");
-                chunk = 0;
-                value = NULL;
-                rc = ERROR_FUNCTION_FAILED;
+                chunk = (strlenW(key) + 2)*sizeof(WCHAR);
+                value = HeapAlloc(GetProcessHeap(),0,chunk);
+                memcpy(value,progress,chunk);
             }
-            break;
-        default:
-            /* check for numeric values */
-            index = 0;
-            while (isdigitW(key[index])) index++;
-            if (key[index] == 0)
+        }
+        else
+        {
+            sz = 0;
+            switch (key[0])
             {
-                index = atoiW(key);
-                TRACE("record index %i\n",index);
-                value = load_dynamic_stringW(record,index);
-                if (value)
-                {
-                    chunk = strlenW(value) * sizeof(WCHAR);
-                    rc = ERROR_SUCCESS;
-                }
-                else
-                {
-                    value = NULL;
-                    rc = ERROR_FUNCTION_FAILED;
-                }
+                case '~':
+                    value = deformat_NULL(&chunk);
+                break;
+                case '$':
+                    value = deformat_component(package,&key[1],&chunk);
+                break;
+                case '#':
+                case '!': /* should be short path */
+                    value = deformat_file(package,&key[1], &chunk);
+                break;
+                case '\\':
+                    value = deformat_escape(&key[1],&chunk);
+                break;
+                case '%':
+                    value = deformat_environment(package,&key[1],&chunk);
+                break;
+                default:
+                    if (is_key_number(key))
+                        value = deformat_index(record,key,&chunk);
+                    else
+                        value = deformat_property(package,key,&chunk);
+                break;      
             }
+        }
+        if (value!=NULL)
+        {
+            LPBYTE nd2;
+            TRACE("value %s, chunk %li size %li\n",debugstr_w((LPWSTR)value),
+                    chunk, size);
+            if (size)
+                nd2= HeapReAlloc(GetProcessHeap(),0,newdata,(size + chunk));
             else
-            {
-                value = load_dynamic_property(package,key, &rc);
-                if (rc == ERROR_SUCCESS)
-                    chunk = (strlenW(value)) * sizeof(WCHAR);
-            }
-            break;      
-    }
-    if (((rc == ERROR_SUCCESS) || (rc == ERROR_MORE_DATA)) && value!=NULL)
-    {
-        LPWSTR nd2;
-        TRACE("value %s, chunk %li size %li\n",debugstr_w(value),chunk,size);
+                nd2= HeapAlloc(GetProcessHeap(),0,chunk);
+            newdata = nd2;
+            memcpy(&newdata[size],value,chunk);
+            size+=chunk;   
+            HeapFree(GetProcessHeap(),0,value);
+        }
 
-        nd2= HeapReAlloc(GetProcessHeap(),0,newdata,(size + chunk));
-        newdata = nd2;
-        memcpy(&newdata[(size/sizeof(WCHAR))],value,chunk);
-        size+=chunk;   
-        HeapFree(GetProcessHeap(),0,value);
-    }
-    TRACE("after value %s .. %s\n",debugstr_w(newdata),debugstr_w(mark));
-    if (mark - ptr < len)
-    {
-        LPWSTR nd2;
-        chunk = (len - (mark - ptr)) * sizeof(WCHAR);
-        TRACE("after chunk is %li\n",chunk);
-        nd2 = HeapReAlloc(GetProcessHeap(),0,newdata,(size+chunk));
-        newdata = nd2;
-        memcpy(&newdata[(size/sizeof(WCHAR))],mark,chunk);
-        size+=chunk;
+        progress = mark2+1;
     }
-    TRACE("after trailing %s .. %s\n",debugstr_w(newdata),debugstr_w(mark));
 
-    /* recursively do this to clean up */
-    size = deformat_string_internal(package,newdata,data,(size/sizeof(WCHAR)),
-                                    record);
-    HeapFree(GetProcessHeap(),0,newdata);
-    return size;
+    TRACE("after everything %s\n",debugstr_w((LPWSTR)newdata));
+
+    *data = (LPWSTR)newdata;
+    return size / sizeof(WCHAR);
 }
 
 
-UINT MSI_FormatRecordW(MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer,
-                        DWORD *size)
+UINT MSI_FormatRecordW( MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer,
+                        DWORD *size )
 {
     LPWSTR deformated;
     LPWSTR rec;
@@ -256,77 +376,147 @@
 
     rec = load_dynamic_stringW(record,0);
     if (!rec)
-        return rc;
+        rec = build_default_format(record);
 
     TRACE("(%s)\n",debugstr_w(rec));
 
-    len = deformat_string_internal(package,rec,&deformated,(strlenW(rec)+1),
+    len = deformat_string_internal(package,rec,&deformated,strlenW(rec),
                                    record);
-    if (len <= *size)
+
+    if (buffer)
     {
-        *size = len;
-        memcpy(buffer,deformated,len*sizeof(WCHAR));
-        rc = ERROR_SUCCESS;
+        if (*size>len)
+        {
+            memcpy(buffer,deformated,len*sizeof(WCHAR));
+            rc = ERROR_SUCCESS;
+            buffer[len] = 0;
+        }
+        else
+        {
+            memcpy(buffer,deformated,(*size)*sizeof(WCHAR));
+            rc = ERROR_MORE_DATA;
+            buffer[(*size)-1] = 0;    
+        }
     }
     else
+        rc = ERROR_SUCCESS;
+
+    *size = len;
+
+    HeapFree(GetProcessHeap(),0,rec);
+    HeapFree(GetProcessHeap(),0,deformated);
+    return rc;
+}
+
+UINT MSI_FormatRecordA( MSIPACKAGE* package, MSIRECORD* record, LPSTR buffer,
+                        DWORD *size )
+{
+    LPWSTR deformated;
+    LPWSTR rec;
+    DWORD len,lenA;
+    UINT rc = ERROR_INVALID_PARAMETER;
+
+    TRACE("%p %p %p %li\n",package, record ,buffer, *size);
+
+    rec = load_dynamic_stringW(record,0);
+    if (!rec)
+        rec = build_default_format(record);
+
+    TRACE("(%s)\n",debugstr_w(rec));
+
+    len = deformat_string_internal(package,rec,&deformated,strlenW(rec),
+                                   record);
+    lenA = WideCharToMultiByte(CP_ACP,0,deformated,len,NULL,0,NULL,NULL);
+
+    if (buffer)
     {
-        *size = len;
-        rc = ERROR_MORE_DATA;
+        WideCharToMultiByte(CP_ACP,0,deformated,len,buffer,*size,NULL, NULL);
+        if (*size>lenA)
+        {
+            rc = ERROR_SUCCESS;
+            buffer[lenA] = 0;
+        }
+        else
+        {
+            rc = ERROR_MORE_DATA;
+            buffer[(*size)-1] = 0;    
+        }
     }
+    else
+        rc = ERROR_SUCCESS;
+
+    *size = lenA;
 
     HeapFree(GetProcessHeap(),0,rec);
     HeapFree(GetProcessHeap(),0,deformated);
     return rc;
 }
 
-UINT WINAPI MsiFormatRecordA(MSIHANDLE hInstall, MSIHANDLE hRecord, LPSTR
-szResult, DWORD *sz)
+
+UINT WINAPI MsiFormatRecordW( MSIHANDLE hInstall, MSIHANDLE hRecord, 
+                              LPWSTR szResult, DWORD *sz )
 {
-    UINT rc;
-    MSIPACKAGE* package;
-    MSIRECORD* record;
-    LPWSTR szwResult;
-    DWORD original_len;
+    UINT r = ERROR_INVALID_HANDLE;
+    MSIPACKAGE *package;
+    MSIRECORD *record;
 
     TRACE("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
 
-    package = msihandle2msiinfo(hInstall,MSIHANDLETYPE_PACKAGE);
-    record = msihandle2msiinfo(hRecord,MSIHANDLETYPE_RECORD);
+    record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
 
-    if (!package || !record)
+    if (!record)
         return ERROR_INVALID_HANDLE;
+    if (!sz)
+    {
+        msiobj_release( &record->hdr );
+        if (szResult)
+            return ERROR_INVALID_PARAMETER;
+        else
+            return ERROR_SUCCESS;
+    }
 
-    original_len = *sz;
-    /* +1 just to make sure we have a buffer in case the len is 0 */
-    szwResult = HeapAlloc(GetProcessHeap(),0,(original_len+1) * sizeof(WCHAR));
-
-    rc = MSI_FormatRecordW(package, record, szwResult, sz);
-    
-    WideCharToMultiByte(CP_ACP,0,szwResult,original_len, szResult, original_len,
-                        NULL,NULL);
-
-    HeapFree(GetProcessHeap(),0,szwResult);
-
-    return rc;
+    package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
 
+    if( record )
+    {
+        r = MSI_FormatRecordW( package, record, szResult, sz );
+        msiobj_release( &record->hdr );
+    }
+    if (package)
+        msiobj_release( &package->hdr );
+    return r;
 }
 
-UINT WINAPI MsiFormatRecordW(MSIHANDLE hInstall, MSIHANDLE hRecord, 
-                             LPWSTR szResult, DWORD *sz)
+UINT WINAPI MsiFormatRecordA( MSIHANDLE hInstall, MSIHANDLE hRecord,
+                              LPSTR szResult, DWORD *sz )
 {
-    UINT rc;
-    MSIPACKAGE* package;
-    MSIRECORD* record;
+    UINT r = ERROR_INVALID_HANDLE;
+    MSIPACKAGE *package = NULL;
+    MSIRECORD *record = NULL;
 
     TRACE("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
 
-    package = msihandle2msiinfo(hInstall,MSIHANDLETYPE_PACKAGE);
-    record = msihandle2msiinfo(hRecord,MSIHANDLETYPE_RECORD);
+    record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
 
-    if (!package || !record)
+    if (!record)
         return ERROR_INVALID_HANDLE;
+    if (!sz)
+    {
+        msiobj_release( &record->hdr );
+        if (szResult)
+            return ERROR_INVALID_PARAMETER;
+        else
+            return ERROR_SUCCESS;
+    }
 
-    rc = MSI_FormatRecordW(package, record, szResult, sz);
+    package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
 
-    return rc;
+    if( record )
+    {
+        r = MSI_FormatRecordA( package, record, szResult, sz );
+        msiobj_release( &record->hdr );
+    }
+    if (package)
+        msiobj_release( &package->hdr );
+    return r;
 }


More information about the wine-patches mailing list