in function deformat_environment did cut of one letter of GetEnvironmentVariableW...
[reactos.git] / reactos / lib / msi / format.c
index 22f11dc..c280541 100644 (file)
@@ -31,26 +31,22 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msifo
 #include "windef.h"
 #include "winbase.h"
 #include "winerror.h"
-#include "winreg.h"
 #include "wine/debug.h"
-#include "fdi.h"
 #include "msi.h"
-#include "msiquery.h"
-#include "fcntl.h"
-#include "objbase.h"
-#include "objidl.h"
 #include "msipriv.h"
 #include "winnls.h"
-#include "winuser.h"
-#include "shlobj.h"
 #include "wine/unicode.h"
-#include "ver.h"
 #include "action.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
 
-LPWSTR build_default_format(MSIRECORD* record)
+static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, 
+                                     WCHAR** data, DWORD len, MSIRECORD* record,
+                                     BOOL* in_group);
+
+
+static LPWSTR build_default_format(MSIRECORD* record)
 {
     int i;  
     int count;
@@ -60,7 +56,7 @@ LPWSTR build_default_format(MSIRECORD* record)
 
     count = MSI_RecordGetFieldCount(record);
 
-    rc = HeapAlloc(GetProcessHeap(),0,(11*count)*sizeof(WCHAR));
+    rc = msi_alloc((11*count)*sizeof(WCHAR));
     rc[0] = 0;
     for (i = 1; i <= count; i++)
     {
@@ -83,39 +79,62 @@ static const WCHAR* scanW(LPCWSTR buf, WCHAR token, DWORD len)
 static LPWSTR deformat_component(MSIPACKAGE* package, LPCWSTR key, DWORD* sz)
 {
     LPWSTR value = NULL;
-    INT index;
+    MSICOMPONENT *comp;
 
     *sz = 0;
     if (!package)
         return NULL;
 
-    ERR("POORLY HANDLED DEFORMAT.. [$componentkey] \n");
-    index = get_loaded_component(package,key);
-    if (index >= 0)
+    FIXME("component key %s\n", debugstr_w(key));
+    comp = get_loaded_component(package,key);
+    if (comp)
     {
-        value = resolve_folder(package, package->components[index].Directory, 
-                                       FALSE, FALSE, NULL);
+        value = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
         *sz = (strlenW(value)) * sizeof(WCHAR);
     }
 
     return value;
 }
 
-static LPWSTR deformat_file(MSIPACKAGE* package, LPCWSTR key, DWORD* sz)
+static LPWSTR deformat_file(MSIPACKAGE* package, LPCWSTR key, DWORD* sz, 
+                            BOOL shortname)
 {
     LPWSTR value = NULL;
-    INT index;
+    MSIFILE *file;
 
     *sz = 0;
 
     if (!package)
         return NULL;
 
-    index = get_loaded_file(package,key);
-    if (index >=0)
+    file = get_loaded_file( package, key );
+    if (file)
     {
-        value = dupstrW(package->files[index].TargetPath);
-        *sz = (strlenW(value)) * sizeof(WCHAR);
+        if (!shortname)
+        {
+            value = strdupW( file->TargetPath );
+            *sz = (strlenW(value)) * sizeof(WCHAR);
+        }
+        else
+        {
+            DWORD size = 0;
+            size = GetShortPathNameW( file->TargetPath, NULL, 0 );
+
+            if (size > 0)
+            {
+                *sz = (size-1) * sizeof (WCHAR);
+                size ++;
+                value = msi_alloc(size * sizeof(WCHAR));
+                GetShortPathNameW( file->TargetPath, value, size );
+            }
+            else
+            {
+                ERR("Unable to get ShortPath size (%s)\n",
+                    debugstr_w( file->TargetPath) );
+                value = NULL;
+                *sz = 0;
+            }
+        }
     }
 
     return value;
@@ -131,13 +150,13 @@ static LPWSTR deformat_environment(MSIPACKAGE* package, LPCWSTR key,
     if (sz > 0)
     {
         sz++;
-        value = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR));
-        GetEnvironmentVariableW(&key[1],value,sz);
+        value = msi_alloc(sz * sizeof(WCHAR));
+        GetEnvironmentVariableW(key,value,sz);
         *chunk = (strlenW(value)) * sizeof(WCHAR);
     }
     else
     {
-        ERR("Unknown environment variable\n");
+        ERR("Unknown environment variable %s\n", debugstr_w(key));
         *chunk = 0;
         value = NULL;
     }
@@ -149,7 +168,7 @@ static LPWSTR deformat_NULL(DWORD* chunk)
 {
     LPWSTR value;
 
-    value = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*2);
+    value = msi_alloc(sizeof(WCHAR)*2);
     value[0] =  0;
     *chunk = sizeof(WCHAR);
     return value;
@@ -159,7 +178,7 @@ static LPWSTR deformat_escape(LPCWSTR key, DWORD* chunk)
 {
     LPWSTR value;
 
-    value = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*2);
+    value = msi_alloc(sizeof(WCHAR)*2);
     value[0] =  key[0];
     *chunk = sizeof(WCHAR);
 
@@ -187,7 +206,7 @@ static LPWSTR deformat_index(MSIRECORD* record, LPCWSTR key, DWORD* chunk )
 
     index = atoiW(key);
     TRACE("record index %i\n",index);
-    value = load_dynamic_stringW(record,index);
+    value = msi_dup_record_field(record,index);
     if (value)
         *chunk = strlenW(value) * sizeof(WCHAR);
     else
@@ -200,20 +219,58 @@ static LPWSTR deformat_index(MSIRECORD* record, LPCWSTR key, DWORD* chunk )
 
 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);
+    value = msi_dup_property( package, key );
 
-    if (rc == ERROR_SUCCESS)
+    if (value)
         *chunk = (strlenW(value)) * sizeof(WCHAR);
 
     return value;
 }
 
+/*
+ * Groups cannot be nested. They are just treated as from { to next } 
+ */
+static BOOL find_next_group(LPCWSTR source, DWORD len_remaining,
+                                    LPWSTR *group, LPCWSTR *mark, 
+                                    LPCWSTR* mark2)
+{
+    int i;
+    BOOL found = FALSE;
+
+    *mark = scanW(source,'{',len_remaining);
+    if (!*mark)
+        return FALSE;
+
+    for (i = 1; (*mark - source) + i < len_remaining; i++)
+    {
+        if ((*mark)[i] == '}')
+        {
+            found = TRUE;
+            break;
+        }
+    }
+    if (! found)
+        return FALSE;
+
+    *mark2 = &(*mark)[i]; 
+
+    i = *mark2 - *mark;
+    *group = msi_alloc(i*sizeof(WCHAR));
+
+    i -= 1;
+    memcpy(*group,&(*mark)[1],i*sizeof(WCHAR));
+    (*group)[i] = 0;
+
+    TRACE("Found group %s\n",debugstr_w(*group));
+    return TRUE;
+}
+
+
 static BOOL find_next_outermost_key(LPCWSTR source, DWORD len_remaining,
                                     LPWSTR *key, LPCWSTR *mark, LPCWSTR* mark2, 
                                     BOOL *nested)
@@ -249,23 +306,82 @@ static BOOL find_next_outermost_key(LPCWSTR source, DWORD len_remaining,
     *mark2 = &(*mark)[i-1]; 
 
     i = *mark2 - *mark;
-    *key = HeapAlloc(GetProcessHeap(),0,i*sizeof(WCHAR));
+    *key = msi_alloc(i*sizeof(WCHAR));
     /* do not have the [] in the key */
     i -= 1;
-    strncpyW(*key,&(*mark)[1],i);
+    memcpy(*key,&(*mark)[1],i*sizeof(WCHAR));
     (*key)[i] = 0;
 
     TRACE("Found Key %s\n",debugstr_w(*key));
     return TRUE;
 }
 
+static LPWSTR deformat_group(MSIPACKAGE* package, LPWSTR group, DWORD len, 
+                      MSIRECORD* record, DWORD* size)
+{
+    LPWSTR value = NULL;
+    LPCWSTR mark, mark2;
+    LPWSTR key;
+    BOOL nested;
+    INT failcount;
+    static const WCHAR fmt[] = {'{','%','s','}',0};
+    UINT sz;
+
+    if (!group || group[0] == 0) 
+    {
+        *size = 0;
+        return NULL;
+    }
+    /* if no [] then group is returned as is */
+
+     if (!find_next_outermost_key(group, len, &key, &mark, &mark2, &nested))
+     {
+         *size = (len+2)*sizeof(WCHAR);
+         value = msi_alloc(*size);
+         sprintfW(value,fmt,group);
+         /* do not return size of the null at the end */
+         *size = (len+1)*sizeof(WCHAR);
+         return value;
+     }
+
+     msi_free(key);
+     failcount = 0;
+     sz = deformat_string_internal(package, group, &value, strlenW(group),
+                                     record, &failcount);
+     if (failcount==0)
+     {
+        *size = sz * sizeof(WCHAR);
+        return value;
+     }
+     else if (failcount < 0)
+     {
+         LPWSTR v2;
+
+         v2 = msi_alloc((sz+2)*sizeof(WCHAR));
+         v2[0] = '{';
+         memcpy(&v2[1],value,sz*sizeof(WCHAR));
+         v2[sz+1]='}';
+         msi_free(value);
+
+         *size = (sz+2)*sizeof(WCHAR);
+         return v2;
+     }
+     else
+     {
+         msi_free(value);
+         *size = 0;
+         return NULL;
+     }
+}
+
 
 /*
  * len is in WCHARs
  * return is also in WCHARs
  */
 static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, 
-                                     WCHAR** data, DWORD len, MSIRECORD* record)
+                                     WCHAR** data, DWORD len, MSIRECORD* record,
+                                     INT* failcount)
 {
     LPCWSTR mark = NULL;
     LPCWSTR mark2 = NULL;
@@ -285,15 +401,16 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
         return 0;
     }
 
-    TRACE("Starting with %s\n",debugstr_w(ptr));
+    TRACE("Starting with %s\n",debugstr_wn(ptr,len));
 
     /* scan for special characters... fast exit */
-    if (!scanW(ptr,'[',len) || (scanW(ptr,'[',len) && !scanW(ptr,']',len)))
+    if ((!scanW(ptr,'[',len) || (scanW(ptr,'[',len) && !scanW(ptr,']',len))) && 
+        (scanW(ptr,'{',len) && !scanW(ptr,'}',len)))
     {
         /* not formatted */
-        *data = HeapAlloc(GetProcessHeap(),0,(len*sizeof(WCHAR)));
+        *data = msi_alloc((len*sizeof(WCHAR)));
         memcpy(*data,ptr,len*sizeof(WCHAR));
-        TRACE("Returning %s\n",debugstr_w(*data));
+        TRACE("Returning %s\n",debugstr_wn(*data,len));
         return len;
     }
   
@@ -301,20 +418,30 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
 
     while (progress - ptr < len)
     {
+        /* seek out first group if existing */
+        if (find_next_group(progress, len - (progress - ptr), &key,
+                                &mark, &mark2))
+        {
+            value = deformat_group(package, key, strlenW(key)+1, record, 
+                            &chunk);
+            msi_free( key );
+            key = NULL;
+            nested = FALSE;
+        }
         /* formatted string located */
-        if (!find_next_outermost_key(progress, len - (progress - ptr), &key,
-                                     &mark, &mark2, &nested))
+        else if (!find_next_outermost_key(progress, len - (progress - ptr), 
+                                &key, &mark, &mark2, &nested))
         {
             LPBYTE nd2;
 
-            TRACE("after value %s .. %s\n",debugstr_w((LPWSTR)newdata),
-                                       debugstr_w(mark));
+            TRACE("after value %s\n", debugstr_wn((LPWSTR)newdata,
+                                    size/sizeof(WCHAR)));
             chunk = (len - (progress - ptr)) * sizeof(WCHAR);
             TRACE("after chunk is %li + %li\n",size,chunk);
             if (size)
-                nd2 = HeapReAlloc(GetProcessHeap(),0,newdata,(size+chunk));
+                nd2 = msi_realloc(newdata,(size+chunk));
             else
-                nd2 = HeapAlloc(GetProcessHeap(),0,chunk);
+                nd2 = msi_alloc(chunk);
 
             newdata = nd2;
             memcpy(&newdata[size],progress,chunk);
@@ -330,9 +457,9 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
             TRACE("%i  (%i) characters before marker\n",cnt,(mark-progress));
             size += cnt * sizeof(WCHAR);
             if (!old_size)
-                tgt = HeapAlloc(GetProcessHeap(),0,size);
+                tgt = msi_alloc(size);
             else
-                tgt = HeapReAlloc(GetProcessHeap(),0,newdata,size);
+                tgt = msi_realloc(newdata,size);
             newdata  = tgt;
             memcpy(&newdata[old_size],progress,(cnt * sizeof(WCHAR)));  
         }
@@ -343,32 +470,43 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
         {
             TRACE("Nested key... %s\n",debugstr_w(key));
             deformat_string_internal(package, key, &value, strlenW(key)+1,
-                                     record);
+                                     record, failcount);
 
-            HeapFree(GetProcessHeap(),0,key);
+            msi_free(key);
             key = value;
         }
 
-        TRACE("Current %s .. %s\n",debugstr_w((LPWSTR)newdata),debugstr_w(key));
+        TRACE("Current %s .. %s\n",debugstr_wn((LPWSTR)newdata, 
+                                size/sizeof(WCHAR)),debugstr_w(key));
 
         if (!package)
         {
             /* only deformat number indexs */
-            if (is_key_number(key))
+            if (key && is_key_number(key))
+            {
                 value = deformat_index(record,key,&chunk);  
+                if (!chunk && failcount && *failcount >= 0)
+                    (*failcount)++;
+            }
             else
             {
-                chunk = (strlenW(key) + 2)*sizeof(WCHAR);
-                value = HeapAlloc(GetProcessHeap(),0,chunk);
-                value[0] = '[';
-                memcpy(&value[1],key,strlenW(key)*sizeof(WCHAR));
-                value[strlenW(key)+1] = ']';
+                if (failcount)
+                    *failcount = -1;
+                if(key)
+                {
+                    DWORD keylen = strlenW(key);
+                    chunk = (keylen + 2)*sizeof(WCHAR);
+                    value = msi_alloc(chunk);
+                    value[0] = '[';
+                    memcpy(&value[1],key,keylen*sizeof(WCHAR));
+                    value[1+keylen] = ']';
+                }
             }
         }
         else
         {
             sz = 0;
-            switch (key[0])
+            if (key) switch (key[0])
             {
                 case '~':
                     value = deformat_NULL(&chunk);
@@ -377,8 +515,10 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
                     value = deformat_component(package,&key[1],&chunk);
                 break;
                 case '#':
+                    value = deformat_file(package,&key[1], &chunk, FALSE);
+                break;
                 case '!': /* should be short path */
-                    value = deformat_file(package,&key[1], &chunk);
+                    value = deformat_file(package,&key[1], &chunk, TRUE);
                 break;
                 case '\\':
                     value = deformat_escape(&key[1],&chunk);
@@ -387,15 +527,24 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
                     value = deformat_environment(package,&key[1],&chunk);
                 break;
                 default:
+                    /* index keys cannot be nested */
                     if (is_key_number(key))
-                        value = deformat_index(record,key,&chunk);
+                        if (!nested)
+                            value = deformat_index(record,key,&chunk);
+                        else
+                        {
+                            static const WCHAR fmt[] = {'[','%','s',']',0};
+                            value = msi_alloc(10);
+                            sprintfW(value,fmt,key);
+                            chunk = strlenW(value)*sizeof(WCHAR);
+                        }
                     else
                         value = deformat_property(package,key,&chunk);
                 break;      
             }
         }
 
-        HeapFree(GetProcessHeap(),0,key);
+        msi_free(key);
 
         if (value!=NULL)
         {
@@ -403,19 +552,22 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
             TRACE("value %s, chunk %li size %li\n",debugstr_w((LPWSTR)value),
                     chunk, size);
             if (size)
-                nd2= HeapReAlloc(GetProcessHeap(),0,newdata,(size + chunk));
+                nd2= msi_realloc(newdata,(size + chunk));
             else
-                nd2= HeapAlloc(GetProcessHeap(),0,chunk);
+                nd2= msi_alloc(chunk);
             newdata = nd2;
             memcpy(&newdata[size],value,chunk);
             size+=chunk;   
-            HeapFree(GetProcessHeap(),0,value);
+            msi_free(value);
         }
+        else if (failcount && *failcount >=0 )
+            (*failcount)++;
 
         progress = mark2+1;
     }
 
-    TRACE("after everything %s\n",debugstr_w((LPWSTR)newdata));
+    TRACE("after everything %s\n",debugstr_wn((LPWSTR)newdata, 
+                            size/sizeof(WCHAR)));
 
     *data = (LPWSTR)newdata;
     return size / sizeof(WCHAR);
@@ -432,14 +584,14 @@ UINT MSI_FormatRecordW( MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer,
 
     TRACE("%p %p %p %li\n",package, record ,buffer, *size);
 
-    rec = load_dynamic_stringW(record,0);
+    rec = msi_dup_record_field(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);
+                                   record, NULL);
 
     if (buffer)
     {
@@ -464,8 +616,8 @@ UINT MSI_FormatRecordW( MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer,
 
     *size = len;
 
-    HeapFree(GetProcessHeap(),0,rec);
-    HeapFree(GetProcessHeap(),0,deformated);
+    msi_free(rec);
+    msi_free(deformated);
     return rc;
 }
 
@@ -479,14 +631,14 @@ UINT MSI_FormatRecordA( MSIPACKAGE* package, MSIRECORD* record, LPSTR buffer,
 
     TRACE("%p %p %p %li\n",package, record ,buffer, *size);
 
-    rec = load_dynamic_stringW(record,0);
+    rec = msi_dup_record_field(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);
+                                   record, NULL);
     lenA = WideCharToMultiByte(CP_ACP,0,deformated,len,NULL,0,NULL,NULL);
 
     if (buffer)
@@ -508,8 +660,8 @@ UINT MSI_FormatRecordA( MSIPACKAGE* package, MSIRECORD* record, LPSTR buffer,
 
     *size = lenA;
 
-    HeapFree(GetProcessHeap(),0,rec);
-    HeapFree(GetProcessHeap(),0,deformated);
+    msi_free(rec);
+    msi_free(deformated);
     return rc;
 }