[WBEMPROX] Sync with Wine Staging 1.9.4. CORE-10912
[reactos.git] / reactos / dll / win32 / wbemprox / query.c
index 6ad7f4d..3e37f42 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#define WIN32_NO_STATUS
-#define _INC_WINDOWS
-#define COM_NO_WINDOWS_H
-
-#define COBJMACROS
-
-#include "config.h"
-#include <stdarg.h>
-
-#include "windef.h"
-#include "winbase.h"
-#include "objbase.h"
-#include "oleauto.h"
-#include "wbemcli.h"
-
-#include "wine/debug.h"
 #include "wbemprox_private.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(wbemprox);
+#include <winuser.h>
 
 HRESULT create_view( const struct property *proplist, const WCHAR *class,
                      const struct expr *cond, struct view **ret )
@@ -69,10 +53,10 @@ static BOOL eval_like( const WCHAR *lstr, const WCHAR *rstr )
         {
             while (*q == '%') q++;
             if (!*q) return TRUE;
-            while (*p && toupperW( p[1] ) != toupperW( q[1] )) p++;
-            if (!*p) return TRUE;
+            while (*p && *q && toupperW( *p ) == toupperW( *q )) { p++; q++; };
+            if (!*p && !*q) return TRUE;
         }
-        if (toupperW( *p++ ) != toupperW( *q++ )) return FALSE;
+        if (*q != '%' && toupperW( *p++ ) != toupperW( *q++ )) return FALSE;
     }
     return TRUE;
 }
@@ -114,28 +98,166 @@ static HRESULT eval_strcmp( UINT op, const WCHAR *lstr, const WCHAR *rstr, LONGL
     return S_OK;
 }
 
-static inline BOOL is_strcmp( const struct complex_expr *expr )
+static BOOL is_int( CIMTYPE type )
 {
-    return ((expr->left->type == EXPR_PROPVAL && expr->right->type == EXPR_SVAL) ||
-            (expr->left->type == EXPR_SVAL && expr->right->type == EXPR_PROPVAL));
+    switch (type)
+    {
+    case CIM_SINT8:
+    case CIM_SINT16:
+    case CIM_SINT32:
+    case CIM_SINT64:
+    case CIM_UINT8:
+    case CIM_UINT16:
+    case CIM_UINT32:
+    case CIM_UINT64:
+        return TRUE;
+    default:
+        return FALSE;
+    }
+}
+
+static inline BOOL is_strcmp( const struct complex_expr *expr, UINT ltype, UINT rtype )
+{
+    if ((ltype == CIM_STRING || is_int( ltype )) && expr->left->type == EXPR_PROPVAL &&
+        expr->right->type == EXPR_SVAL) return TRUE;
+    else if ((rtype == CIM_STRING || is_int( rtype )) && expr->right->type == EXPR_PROPVAL &&
+             expr->left->type == EXPR_SVAL) return TRUE;
+    return FALSE;
+}
+
+static inline BOOL is_boolcmp( const struct complex_expr *expr, UINT ltype, UINT rtype )
+{
+    if (ltype == CIM_BOOLEAN && expr->left->type == EXPR_PROPVAL &&
+        (expr->right->type == EXPR_SVAL || expr->right->type == EXPR_BVAL)) return TRUE;
+    else if (rtype == CIM_BOOLEAN && expr->right->type == EXPR_PROPVAL &&
+             (expr->left->type == EXPR_SVAL || expr->left->type == EXPR_BVAL)) return TRUE;
+    return FALSE;
+}
+
+static HRESULT eval_boolcmp( UINT op, LONGLONG lval, LONGLONG rval, UINT ltype, UINT rtype, LONGLONG *val )
+{
+    static const WCHAR trueW[] = {'T','r','u','e',0};
+
+    if (ltype == CIM_STRING) lval = !strcmpiW( (const WCHAR *)(INT_PTR)lval, trueW ) ? -1 : 0;
+    else if (rtype == CIM_STRING) rval = !strcmpiW( (const WCHAR *)(INT_PTR)rval, trueW ) ? -1 : 0;
+
+    switch (op)
+    {
+    case OP_EQ:
+        *val = (lval == rval);
+        break;
+    case OP_NE:
+        *val = (lval != rval);
+        break;
+    default:
+        ERR("unhandled operator %u\n", op);
+        return WBEM_E_INVALID_QUERY;
+    }
+    return S_OK;
+}
+
+static UINT resolve_type( UINT left, UINT right )
+{
+    switch (left)
+    {
+    case CIM_SINT8:
+    case CIM_SINT16:
+    case CIM_SINT32:
+    case CIM_SINT64:
+    case CIM_UINT8:
+    case CIM_UINT16:
+    case CIM_UINT32:
+    case CIM_UINT64:
+        switch (right)
+        {
+            case CIM_SINT8:
+            case CIM_SINT16:
+            case CIM_SINT32:
+            case CIM_SINT64:
+            case CIM_UINT8:
+            case CIM_UINT16:
+            case CIM_UINT32:
+            case CIM_UINT64:
+                return CIM_UINT64;
+            default: break;
+        }
+        break;
+
+    case CIM_STRING:
+        if (right == CIM_STRING) return CIM_STRING;
+        break;
+
+    case CIM_BOOLEAN:
+        if (right == CIM_BOOLEAN) return CIM_BOOLEAN;
+        break;
+
+    default:
+        break;
+    }
+    return CIM_ILLEGAL;
 }
 
-static HRESULT eval_cond( const struct table *, UINT, const struct expr *, LONGLONG * );
+static const WCHAR *format_int( WCHAR *buf, CIMTYPE type, LONGLONG val )
+{
+    static const WCHAR fmt_signedW[] = {'%','d',0};
+    static const WCHAR fmt_unsignedW[] = {'%','u',0};
+    static const WCHAR fmt_signed64W[] = {'%','I','6','4','d',0};
+    static const WCHAR fmt_unsigned64W[] = {'%','I','6','4','u',0};
+
+    switch (type)
+    {
+    case CIM_SINT8:
+    case CIM_SINT16:
+    case CIM_SINT32:
+        sprintfW( buf, fmt_signedW, val );
+        return buf;
+
+    case CIM_UINT8:
+    case CIM_UINT16:
+    case CIM_UINT32:
+        sprintfW( buf, fmt_unsignedW, val );
+        return buf;
+
+    case CIM_SINT64:
+        wsprintfW( buf, fmt_signed64W, val );
+        return buf;
+
+    case CIM_UINT64:
+        wsprintfW( buf, fmt_unsigned64W, val );
+        return buf;
+
+    default:
+        ERR( "unhandled type %u\n", type );
+        return NULL;
+    }
+}
 
 static HRESULT eval_binary( const struct table *table, UINT row, const struct complex_expr *expr,
-                            LONGLONG *val )
+                            LONGLONG *val, UINT *type )
 {
     HRESULT lret, rret;
     LONGLONG lval, rval;
+    UINT ltype, rtype;
 
-    lret = eval_cond( table, row, expr->left, &lval );
-    rret = eval_cond( table, row, expr->right, &rval );
+    lret = eval_cond( table, row, expr->left, &lval, &ltype );
+    rret = eval_cond( table, row, expr->right, &rval, &rtype );
     if (lret != S_OK || rret != S_OK) return WBEM_E_INVALID_QUERY;
 
-    if (is_strcmp( expr ))
+    *type = resolve_type( ltype, rtype );
+
+    if (is_boolcmp( expr, ltype, rtype ))
+        return eval_boolcmp( expr->op, lval, rval, ltype, rtype, val );
+
+    if (is_strcmp( expr, ltype, rtype ))
     {
-        const WCHAR *lstr = (const WCHAR *)(INT_PTR)lval;
-        const WCHAR *rstr = (const WCHAR *)(INT_PTR)rval;
+        const WCHAR *lstr, *rstr;
+        WCHAR lbuf[21], rbuf[21];
+
+        if (is_int( ltype )) lstr = format_int( lbuf, ltype, lval );
+        else lstr = (const WCHAR *)(INT_PTR)lval;
+
+        if (is_int( rtype )) rstr = format_int( rbuf, rtype, rval );
+        else rstr = (const WCHAR *)(INT_PTR)rval;
 
         return eval_strcmp( expr->op, lstr, rstr, val );
     }
@@ -173,13 +295,22 @@ static HRESULT eval_binary( const struct table *table, UINT row, const struct co
 }
 
 static HRESULT eval_unary( const struct table *table, UINT row, const struct complex_expr *expr,
-                           LONGLONG *val )
+                           LONGLONG *val, UINT *type )
 
 {
     HRESULT hr;
     UINT column;
     LONGLONG lval;
 
+    if (expr->op == OP_NOT)
+    {
+        hr = eval_cond( table, row, expr->left, &lval, type );
+        if (hr != S_OK)
+            return hr;
+        *val = !lval;
+        return S_OK;
+    }
+
     hr = get_column_index( table, expr->left->u.propval->name, &column );
     if (hr != S_OK)
         return hr;
@@ -200,11 +331,13 @@ static HRESULT eval_unary( const struct table *table, UINT row, const struct com
         ERR("unknown operator %u\n", expr->op);
         return WBEM_E_INVALID_QUERY;
     }
+
+    *type = table->columns[column].type & CIM_TYPE_MASK;
     return S_OK;
 }
 
 static HRESULT eval_propval( const struct table *table, UINT row, const struct property *propval,
-                             LONGLONG *val )
+                             LONGLONG *val, UINT *type )
 
 {
     HRESULT hr;
@@ -214,32 +347,44 @@ static HRESULT eval_propval( const struct table *table, UINT row, const struct p
     if (hr != S_OK)
         return hr;
 
+    *type = table->columns[column].type & CIM_TYPE_MASK;
     return get_value( table, row, column, val );
 }
 
-static HRESULT eval_cond( const struct table *table, UINT row, const struct expr *cond,
-                          LONGLONG *val )
+HRESULT eval_cond( const struct table *table, UINT row, const struct expr *cond, LONGLONG *val, UINT *type )
 {
     if (!cond)
     {
         *val = 1;
+        *type = CIM_UINT64;
         return S_OK;
     }
     switch (cond->type)
     {
     case EXPR_COMPLEX:
-        return eval_binary( table, row, &cond->u.expr, val );
+        return eval_binary( table, row, &cond->u.expr, val, type );
+
     case EXPR_UNARY:
-        return eval_unary( table, row, &cond->u.expr, val );
+        return eval_unary( table, row, &cond->u.expr, val, type );
+
     case EXPR_PROPVAL:
-        return eval_propval( table, row, cond->u.propval, val );
+        return eval_propval( table, row, cond->u.propval, val, type );
+
     case EXPR_SVAL:
         *val = (INT_PTR)cond->u.sval;
+        *type = CIM_STRING;
         return S_OK;
+
     case EXPR_IVAL:
+        *val = cond->u.ival;
+        *type = CIM_UINT64;
+        return S_OK;
+
     case EXPR_BVAL:
         *val = cond->u.ival;
+        *type = CIM_BOOLEAN;
         return S_OK;
+
     default:
         ERR("invalid expression type\n");
         break;
@@ -247,11 +392,17 @@ static HRESULT eval_cond( const struct table *table, UINT row, const struct expr
     return WBEM_E_INVALID_QUERY;
 }
 
-static HRESULT execute_view( struct view *view )
+HRESULT execute_view( struct view *view )
 {
     UINT i, j = 0, len;
 
-    if (!view->table || !view->table->num_rows) return S_OK;
+    if (!view->table) return S_OK;
+    if (view->table->fill)
+    {
+        clear_table( view->table );
+        view->table->fill( view->table, view->cond );
+    }
+    if (!view->table->num_rows) return S_OK;
 
     len = min( view->table->num_rows, 16 );
     if (!(view->result = heap_alloc( len * sizeof(UINT) ))) return E_OUTOFMEMORY;
@@ -260,6 +411,7 @@ static HRESULT execute_view( struct view *view )
     {
         HRESULT hr;
         LONGLONG val = 0;
+        UINT type;
 
         if (j >= len)
         {
@@ -268,14 +420,14 @@ static HRESULT execute_view( struct view *view )
             if (!(tmp = heap_realloc( view->result, len * sizeof(UINT) ))) return E_OUTOFMEMORY;
             view->result = tmp;
         }
-        if ((hr = eval_cond( view->table, i, view->cond, &val )) != S_OK) return hr;
+        if ((hr = eval_cond( view->table, i, view->cond, &val, &type )) != S_OK) return hr;
         if (val) view->result[j++] = i;
     }
     view->count = j;
     return S_OK;
 }
 
-static struct query *create_query(void)
+struct query *create_query(void)
 {
     struct query *query;
 
@@ -285,15 +437,13 @@ static struct query *create_query(void)
     return query;
 }
 
-static void free_query( struct query *query )
+void free_query( struct query *query )
 {
     struct list *mem, *next;
 
+    if (!query) return;
     destroy_view( query->view );
-    LIST_FOR_EACH_SAFE( mem, next, &query->mem )
-    {
-        heap_free( mem );
-    }
+    LIST_FOR_EACH_SAFE( mem, next, &query->mem ) { heap_free( mem ); }
     heap_free( query );
 }
 
@@ -319,14 +469,14 @@ HRESULT exec_query( const WCHAR *str, IEnumWbemClassObject **result )
     if (hr != S_OK) goto done;
     hr = execute_view( query->view );
     if (hr != S_OK) goto done;
-    hr = EnumWbemClassObject_create( NULL, query, (void **)result );
+    hr = EnumWbemClassObject_create( query, (void **)result );
 
 done:
     release_query( query );
     return hr;
 }
 
-static BOOL is_selected_prop( const struct view *view, const WCHAR *name )
+BOOL is_selected_prop( const struct view *view, const WCHAR *name )
 {
     const struct property *prop = view->proplist;
 
@@ -465,7 +615,7 @@ done:
     return ret;
 }
 
-static inline BOOL is_method( const struct table *table, UINT column )
+BOOL is_method( const struct table *table, UINT column )
 {
     return table->columns[column].type & COL_FLAG_METHOD;
 }
@@ -566,6 +716,8 @@ VARTYPE to_vartype( CIMTYPE type )
     case CIM_BOOLEAN:  return VT_BOOL;
     case CIM_STRING:
     case CIM_DATETIME: return VT_BSTR;
+    case CIM_SINT8:    return VT_I1;
+    case CIM_UINT8:    return VT_UI1;
     case CIM_SINT16:   return VT_I2;
     case CIM_UINT16:   return VT_UI2;
     case CIM_SINT32:   return VT_I4;
@@ -586,7 +738,7 @@ SAFEARRAY *to_safearray( const struct array *array, CIMTYPE type )
     VARTYPE vartype = to_vartype( type );
     LONG i;
 
-    if (!(ret = SafeArrayCreateVector( vartype, 0, array->count ))) return NULL;
+    if (!array || !(ret = SafeArrayCreateVector( vartype, 0, array->count ))) return NULL;
 
     for (i = 0; i < array->count; i++)
     {
@@ -600,6 +752,7 @@ SAFEARRAY *to_safearray( const struct array *array, CIMTYPE type )
                 SafeArrayDestroy( ret );
                 return NULL;
             }
+            SysFreeString( str );
         }
         else if (SafeArrayPutElement( ret, &i, ptr ) != S_OK)
         {
@@ -626,6 +779,12 @@ void set_variant( VARTYPE type, LONGLONG val, void *val_ptr, VARIANT *ret )
     case VT_BSTR:
         V_BSTR( ret ) = val_ptr;
         break;
+    case VT_I1:
+        V_I1( ret ) = val;
+        break;
+    case VT_UI1:
+        V_UI1( ret ) = val;
+        break;
     case VT_I2:
         V_I2( ret ) = val;
         break;
@@ -672,7 +831,8 @@ HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VAR
         CIMTYPE basetype = view->table->columns[column].type & CIM_TYPE_MASK;
 
         val_ptr = to_safearray( (const struct array *)(INT_PTR)val, basetype );
-        if (!vartype) vartype = to_vartype( basetype ) | VT_ARRAY;
+        if (!val_ptr) vartype = VT_NULL;
+        else if (!vartype) vartype = to_vartype( basetype ) | VT_ARRAY;
         goto done;
     }
     switch (view->table->columns[column].type & COL_TYPE_MASK)
@@ -690,6 +850,12 @@ HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VAR
         else
             vartype = VT_NULL;
         break;
+    case CIM_SINT8:
+        if (!vartype) vartype = VT_I1;
+        break;
+    case CIM_UINT8:
+        if (!vartype) vartype = VT_UI1;
+        break;
     case CIM_SINT16:
         if (!vartype) vartype = VT_I2;
         break;
@@ -728,6 +894,8 @@ static CIMTYPE to_cimtype( VARTYPE type )
     {
     case VT_BOOL:  return CIM_BOOLEAN;
     case VT_BSTR:  return CIM_STRING;
+    case VT_I1:    return CIM_SINT8;
+    case VT_UI1:   return CIM_UINT8;
     case VT_I2:    return CIM_SINT16;
     case VT_UI2:   return CIM_UINT16;
     case VT_I4:    return CIM_SINT32;
@@ -861,26 +1029,35 @@ HRESULT put_propval( const struct view *view, UINT index, const WCHAR *name, VAR
     return set_value( view->table, row, column, val, type );
 }
 
-HRESULT get_properties( const struct view *view, SAFEARRAY **props )
+HRESULT get_properties( const struct view *view, LONG flags, SAFEARRAY **props )
 {
     SAFEARRAY *sa;
     BSTR str;
-    LONG i;
-    UINT num_props = count_properties( view );
+    UINT i, num_props = count_selected_properties( view );
+    LONG j;
 
     if (!(sa = SafeArrayCreateVector( VT_BSTR, 0, num_props ))) return E_OUTOFMEMORY;
 
-    for (i = 0; i < view->table->num_cols; i++)
+    for (i = 0, j = 0; i < view->table->num_cols; i++)
     {
+        BOOL is_system;
+
         if (is_method( view->table, i )) continue;
+        if (!is_selected_prop( view, view->table->columns[i].name )) continue;
+
+        is_system = is_system_prop( view->table->columns[i].name );
+        if ((flags & WBEM_FLAG_NONSYSTEM_ONLY) && is_system) continue;
+        else if ((flags & WBEM_FLAG_SYSTEM_ONLY) && !is_system) continue;
 
         str = SysAllocString( view->table->columns[i].name );
-        if (!str || SafeArrayPutElement( sa, &i, str ) != S_OK)
+        if (!str || SafeArrayPutElement( sa, &j, str ) != S_OK)
         {
             SysFreeString( str );
             SafeArrayDestroy( sa );
             return E_OUTOFMEMORY;
         }
+        SysFreeString( str );
+        j++;
     }
     *props = sa;
     return S_OK;