mshtml: Moved Invoke(DISPID_ENABLED) invocation to separated function.
[wine] / dlls / wbemprox / query.c
1 /*
2  * Copyright 2012 Hans Leidekker for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #define COBJMACROS
20
21 #include "config.h"
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wbemcli.h"
27
28 #include "wine/debug.h"
29 #include "wbemprox_private.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(wbemprox);
32
33 HRESULT create_view( const struct property *proplist, const WCHAR *class,
34                      const struct expr *cond, struct view **ret )
35 {
36     struct view *view = heap_alloc( sizeof(struct view) );
37
38     if (!view) return E_OUTOFMEMORY;
39     view->proplist = proplist;
40     view->table    = get_table( class );
41     view->cond     = cond;
42     view->result   = NULL;
43     view->count    = 0;
44     *ret = view;
45     return S_OK;
46 }
47
48 void destroy_view( struct view *view )
49 {
50     free_table( view->table );
51     heap_free( view->result );
52     heap_free( view );
53 }
54
55 static BOOL eval_like( const WCHAR *lstr, const WCHAR *rstr )
56 {
57     const WCHAR *p = lstr, *q = rstr;
58
59     while (*p && *q)
60     {
61         if (*q == '%')
62         {
63             while (*q == '%') q++;
64             if (!*q) return TRUE;
65             while (*p && toupperW( p[1] ) != toupperW( q[1] )) p++;
66             if (!*p) return TRUE;
67         }
68         if (toupperW( *p++ ) != toupperW( *q++ )) return FALSE;
69     }
70     return TRUE;
71 }
72
73 static HRESULT eval_strcmp( UINT op, const WCHAR *lstr, const WCHAR *rstr, LONGLONG *val )
74 {
75     switch (op)
76     {
77     case OP_EQ:
78         *val = !strcmpW( lstr, rstr );
79         break;
80     case OP_GT:
81         *val = strcmpW( lstr, rstr ) > 0;
82         break;
83     case OP_LT:
84         *val = strcmpW( lstr, rstr ) < 0;
85         break;
86     case OP_LE:
87         *val = strcmpW( lstr, rstr ) <= 0;
88         break;
89     case OP_GE:
90         *val = strcmpW( lstr, rstr ) >= 0;
91         break;
92     case OP_NE:
93         *val = strcmpW( lstr, rstr );
94         break;
95     case OP_LIKE:
96         *val = eval_like( lstr, rstr );
97         break;
98     default:
99         ERR("unhandled operator %u\n", op);
100         return WBEM_E_INVALID_QUERY;
101     }
102     return S_OK;
103 }
104
105 static inline BOOL is_strcmp( const struct complex_expr *expr )
106 {
107     return ((expr->left->type == EXPR_PROPVAL && expr->right->type == EXPR_SVAL) ||
108             (expr->left->type == EXPR_SVAL && expr->right->type == EXPR_PROPVAL));
109 }
110
111 static HRESULT eval_cond( const struct table *, UINT, const struct expr *, LONGLONG * );
112
113 static HRESULT eval_binary( const struct table *table, UINT row, const struct complex_expr *expr,
114                             LONGLONG *val )
115 {
116     HRESULT lret, rret;
117     LONGLONG lval, rval;
118
119     lret = eval_cond( table, row, expr->left, &lval );
120     rret = eval_cond( table, row, expr->right, &rval );
121     if (lret != S_OK || rret != S_OK) return WBEM_E_INVALID_QUERY;
122
123     if (is_strcmp( expr ))
124     {
125         const WCHAR *lstr = (const WCHAR *)(INT_PTR)lval;
126         const WCHAR *rstr = (const WCHAR *)(INT_PTR)rval;
127
128         return eval_strcmp( expr->op, lstr, rstr, val );
129     }
130     switch (expr->op)
131     {
132     case OP_EQ:
133         *val = (lval == rval);
134         break;
135     case OP_AND:
136         *val = (lval && rval);
137         break;
138     case OP_OR:
139         *val = (lval || rval);
140         break;
141     case OP_GT:
142         *val = (lval > rval);
143         break;
144     case OP_LT:
145         *val = (lval < rval);
146         break;
147     case OP_LE:
148         *val = (lval <= rval);
149         break;
150     case OP_GE:
151         *val = (lval >= rval);
152         break;
153     case OP_NE:
154         *val = (lval != rval);
155         break;
156     default:
157         ERR("unhandled operator %u\n", expr->op);
158         return WBEM_E_INVALID_QUERY;
159     }
160     return S_OK;
161 }
162
163 static HRESULT eval_unary( const struct table *table, UINT row, const struct complex_expr *expr,
164                            LONGLONG *val )
165
166 {
167     HRESULT hr;
168     UINT column;
169     LONGLONG lval;
170
171     hr = get_column_index( table, expr->left->u.propval->name, &column );
172     if (hr != S_OK)
173         return hr;
174
175     hr = get_value( table, row, column, &lval );
176     if (hr != S_OK)
177         return hr;
178
179     switch (expr->op)
180     {
181     case OP_ISNULL:
182         *val = !lval;
183         break;
184     case OP_NOTNULL:
185         *val = lval;
186         break;
187     default:
188         ERR("unknown operator %u\n", expr->op);
189         return WBEM_E_INVALID_QUERY;
190     }
191     return S_OK;
192 }
193
194 static HRESULT eval_propval( const struct table *table, UINT row, const struct property *propval,
195                              LONGLONG *val )
196
197 {
198     HRESULT hr;
199     UINT column;
200
201     hr = get_column_index( table, propval->name, &column );
202     if (hr != S_OK)
203         return hr;
204
205     return get_value( table, row, column, val );
206 }
207
208 static HRESULT eval_cond( const struct table *table, UINT row, const struct expr *cond,
209                           LONGLONG *val )
210 {
211     if (!cond)
212     {
213         *val = 1;
214         return S_OK;
215     }
216     switch (cond->type)
217     {
218     case EXPR_COMPLEX:
219         return eval_binary( table, row, &cond->u.expr, val );
220     case EXPR_UNARY:
221         return eval_unary( table, row, &cond->u.expr, val );
222     case EXPR_PROPVAL:
223         return eval_propval( table, row, cond->u.propval, val );
224     case EXPR_SVAL:
225         *val = (LONGLONG)(INT_PTR)cond->u.sval;
226         return S_OK;
227     case EXPR_IVAL:
228     case EXPR_BVAL:
229         *val = cond->u.ival;
230         return S_OK;
231     default:
232         ERR("invalid expression type\n");
233         break;
234     }
235     return WBEM_E_INVALID_QUERY;
236 }
237
238 static HRESULT execute_view( struct view *view )
239 {
240     UINT i, j = 0, len;
241
242     if (!view->table || !view->table->num_rows) return S_OK;
243
244     len = min( view->table->num_rows, 16 );
245     if (!(view->result = heap_alloc( len * sizeof(UINT) ))) return E_OUTOFMEMORY;
246
247     for (i = 0; i < view->table->num_rows; i++)
248     {
249         HRESULT hr;
250         LONGLONG val = 0;
251
252         if (j >= len)
253         {
254             UINT *tmp;
255             len *= 2;
256             if (!(tmp = heap_realloc( view->result, len * sizeof(UINT) ))) return E_OUTOFMEMORY;
257             view->result = tmp;
258         }
259         if ((hr = eval_cond( view->table, i, view->cond, &val )) != S_OK) return hr;
260         if (val) view->result[j++] = i;
261     }
262     view->count = j;
263     return S_OK;
264 }
265
266 static struct query *create_query(void)
267 {
268     struct query *query;
269
270     if (!(query = heap_alloc( sizeof(*query) ))) return NULL;
271     list_init( &query->mem );
272     query->refs = 1;
273     return query;
274 }
275
276 static void free_query( struct query *query )
277 {
278     struct list *mem, *next;
279
280     destroy_view( query->view );
281     LIST_FOR_EACH_SAFE( mem, next, &query->mem )
282     {
283         heap_free( mem );
284     }
285     heap_free( query );
286 }
287
288 void addref_query( struct query *query )
289 {
290     InterlockedIncrement( &query->refs );
291 }
292
293 void release_query( struct query *query )
294 {
295     if (!InterlockedDecrement( &query->refs )) free_query( query );
296 }
297
298 HRESULT exec_query( const WCHAR *str, IEnumWbemClassObject **result )
299 {
300     HRESULT hr;
301     struct query *query;
302
303     *result = NULL;
304     if (!(query = create_query())) return E_OUTOFMEMORY;
305     hr = parse_query( str, &query->view, &query->mem );
306     if (hr != S_OK) goto done;
307     hr = execute_view( query->view );
308     if (hr != S_OK) goto done;
309     hr = EnumWbemClassObject_create( NULL, query, (void **)result );
310
311 done:
312     release_query( query );
313     return hr;
314 }
315
316 static BOOL is_selected_prop( const struct view *view, const WCHAR *name )
317 {
318     const struct property *prop = view->proplist;
319
320     if (!prop) return TRUE;
321     while (prop)
322     {
323         if (!strcmpiW( prop->name, name )) return TRUE;
324         prop = prop->next;
325     }
326     return FALSE;
327 }
328
329 static BOOL is_system_prop( const WCHAR *name )
330 {
331     return (name[0] == '_' && name[1] == '_');
332 }
333
334 static BSTR build_servername( const struct view *view )
335 {
336     WCHAR server[MAX_COMPUTERNAME_LENGTH + 1], *p;
337     DWORD len = sizeof(server)/sizeof(server[0]);
338
339     if (view->proplist) return NULL;
340
341     if (!(GetComputerNameW( server, &len ))) return NULL;
342     for (p = server; *p; p++) *p = toupperW( *p );
343     return SysAllocString( server );
344 }
345
346 static BSTR build_classname( const struct view *view )
347 {
348     return SysAllocString( view->table->name );
349 }
350
351 static BSTR build_namespace( const struct view *view )
352 {
353     static const WCHAR cimv2W[] = {'R','O','O','T','\\','C','I','M','V','2',0};
354
355     if (view->proplist) return NULL;
356     return SysAllocString( cimv2W );
357 }
358
359 static BSTR build_proplist( const struct view *view, UINT index, UINT count, UINT *len )
360 {
361     static const WCHAR fmtW[] = {'%','s','=','%','s',0};
362     UINT i, j, offset, row = view->result[index];
363     BSTR *values, ret = NULL;
364
365     if (!(values = heap_alloc( count * sizeof(BSTR) ))) return NULL;
366
367     *len = j = 0;
368     for (i = 0; i < view->table->num_cols; i++)
369     {
370         if (view->table->columns[i].type & COL_FLAG_KEY)
371         {
372             const WCHAR *name = view->table->columns[i].name;
373
374             values[j] = get_value_bstr( view->table, row, i );
375             *len += strlenW( fmtW ) + strlenW( name ) + strlenW( values[j] );
376             j++;
377         }
378     }
379     if ((ret = SysAllocStringLen( NULL, *len )))
380     {
381         offset = j = 0;
382         for (i = 0; i < view->table->num_cols; i++)
383         {
384             if (view->table->columns[i].type & COL_FLAG_KEY)
385             {
386                 const WCHAR *name = view->table->columns[i].name;
387
388                 offset += sprintfW( ret + offset, fmtW, name, values[j] );
389                 if (j < count - 1) ret[offset++] = ',';
390                 j++;
391             }
392         }
393     }
394     for (i = 0; i < count; i++) SysFreeString( values[i] );
395     heap_free( values );
396     return ret;
397 }
398
399 static UINT count_key_columns( const struct view *view )
400 {
401     UINT i, num_keys = 0;
402
403     for (i = 0; i < view->table->num_cols; i++)
404     {
405         if (view->table->columns[i].type & COL_FLAG_KEY) num_keys++;
406     }
407     return num_keys;
408 }
409
410 static BSTR build_relpath( const struct view *view, UINT index, const WCHAR *name )
411 {
412     static const WCHAR fmtW[] = {'%','s','.','%','s',0};
413     BSTR class, proplist, ret = NULL;
414     UINT num_keys, len;
415
416     if (view->proplist) return NULL;
417
418     if (!(class = build_classname( view ))) return NULL;
419     if (!(num_keys = count_key_columns( view ))) return class;
420     if (!(proplist = build_proplist( view, index, num_keys, &len ))) goto done;
421
422     len += strlenW( fmtW ) + SysStringLen( class );
423     if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
424     sprintfW( ret, fmtW, class, proplist );
425
426 done:
427     SysFreeString( class );
428     SysFreeString( proplist );
429     return ret;
430 }
431
432 static BSTR build_path( const struct view *view, UINT index, const WCHAR *name )
433 {
434     static const WCHAR fmtW[] = {'\\','\\','%','s','\\','%','s',':','%','s',0};
435     BSTR server, namespace = NULL, relpath = NULL, ret = NULL;
436     UINT len;
437
438     if (view->proplist) return NULL;
439
440     if (!(server = build_servername( view ))) return NULL;
441     if (!(namespace = build_namespace( view ))) goto done;
442     if (!(relpath = build_relpath( view, index, name ))) goto done;
443
444     len = strlenW( fmtW ) + SysStringLen( server ) + SysStringLen( namespace ) + SysStringLen( relpath );
445     if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
446     sprintfW( ret, fmtW, server, namespace, relpath );
447
448 done:
449     SysFreeString( server );
450     SysFreeString( namespace );
451     SysFreeString( relpath );
452     return ret;
453 }
454
455 static inline BOOL is_method( const struct table *table, UINT column )
456 {
457     return table->columns[column].type & COL_FLAG_METHOD;
458 }
459
460 static UINT count_properties( const struct view *view )
461 {
462     UINT i, num_props = 0;
463
464     for (i = 0; i < view->table->num_cols; i++)
465     {
466         if (!is_method( view->table, i)) num_props++;
467     }
468     return num_props;
469 }
470
471 static UINT count_selected_properties( const struct view *view )
472 {
473     const struct property *prop = view->proplist;
474     UINT count;
475
476     if (!prop) return count_properties( view );
477
478     count = 1;
479     while ((prop = prop->next)) count++;
480     return count;
481 }
482
483 static HRESULT get_system_propval( const struct view *view, UINT index, const WCHAR *name,
484                                    VARIANT *ret, CIMTYPE *type, LONG *flavor )
485 {
486     static const WCHAR classW[] = {'_','_','C','L','A','S','S',0};
487     static const WCHAR genusW[] = {'_','_','G','E','N','U','S',0};
488     static const WCHAR pathW[] = {'_','_','P','A','T','H',0};
489     static const WCHAR namespaceW[] = {'_','_','N','A','M','E','S','P','A','C','E',0};
490     static const WCHAR propcountW[] = {'_','_','P','R','O','P','E','R','T','Y','_','C','O','U','N','T',0};
491     static const WCHAR relpathW[] = {'_','_','R','E','L','P','A','T','H',0};
492     static const WCHAR serverW[] = {'_','_','S','E','R','V','E','R',0};
493
494     if (flavor) *flavor = WBEM_FLAVOR_ORIGIN_SYSTEM;
495
496     if (!strcmpiW( name, classW ))
497     {
498         V_VT( ret ) = VT_BSTR;
499         V_BSTR( ret ) = build_classname( view );
500         if (type) *type = CIM_STRING;
501         return S_OK;
502     }
503     if (!strcmpiW( name, genusW ))
504     {
505         V_VT( ret ) = VT_I4;
506         V_I4( ret ) = WBEM_GENUS_INSTANCE; /* FIXME */
507         if (type) *type = CIM_SINT32;
508         return S_OK;
509     }
510     else if (!strcmpiW( name, namespaceW ))
511     {
512         V_VT( ret ) = VT_BSTR;
513         V_BSTR( ret ) = build_namespace( view );
514         if (type) *type = CIM_STRING;
515         return S_OK;
516     }
517     else if (!strcmpiW( name, pathW ))
518     {
519         V_VT( ret ) = VT_BSTR;
520         V_BSTR( ret ) = build_path( view, index, name );
521         if (type) *type = CIM_STRING;
522         return S_OK;
523     }
524     if (!strcmpiW( name, propcountW ))
525     {
526         V_VT( ret ) = VT_I4;
527         V_I4( ret ) = count_selected_properties( view );
528         if (type) *type = CIM_SINT32;
529         return S_OK;
530     }
531     else if (!strcmpiW( name, relpathW ))
532     {
533         V_VT( ret ) = VT_BSTR;
534         V_BSTR( ret ) = build_relpath( view, index, name );
535         if (type) *type = CIM_STRING;
536         return S_OK;
537     }
538     else if (!strcmpiW( name, serverW ))
539     {
540         V_VT( ret ) = VT_BSTR;
541         V_BSTR( ret ) = build_servername( view );
542         if (type) *type = CIM_STRING;
543         return S_OK;
544     }
545     FIXME("system property %s not implemented\n", debugstr_w(name));
546     return WBEM_E_NOT_FOUND;
547 }
548
549 static void set_variant( VARTYPE vartype, LONGLONG val, BSTR val_bstr, VARIANT *ret )
550 {
551     switch (vartype)
552     {
553     case VT_BOOL:
554         V_VT( ret ) = VT_BOOL;
555         V_BOOL( ret ) = val;
556         return;
557     case VT_BSTR:
558         V_VT( ret ) = VT_BSTR;
559         V_BSTR( ret ) = val_bstr;
560         return;
561     case VT_I2:
562         V_VT( ret ) = VT_I2;
563         V_I2( ret ) = val;
564         return;
565     case VT_UI2:
566         V_VT( ret ) = VT_UI2;
567         V_UI2( ret ) = val;
568         return;
569     case VT_I4:
570         V_VT( ret ) = VT_I4;
571         V_I4( ret ) = val;
572         return;
573     case VT_UI4:
574         V_VT( ret ) = VT_UI4;
575         V_UI4( ret ) = val;
576         return;
577     case VT_NULL:
578         V_VT( ret ) = VT_NULL;
579         return;
580     default:
581         ERR("unhandled variant type %u\n", vartype);
582         return;
583     }
584 }
585
586 HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *ret,
587                      CIMTYPE *type, LONG *flavor )
588 {
589     HRESULT hr;
590     UINT column, row = view->result[index];
591     VARTYPE vartype;
592     BSTR val_bstr = NULL;
593     LONGLONG val;
594
595     if (is_system_prop( name )) return get_system_propval( view, index, name, ret, type, flavor );
596     if (!is_selected_prop( view, name )) return WBEM_E_NOT_FOUND;
597
598     hr = get_column_index( view->table, name, &column );
599     if (hr != S_OK || is_method( view->table, column )) return WBEM_E_NOT_FOUND;
600
601     vartype = view->table->columns[column].vartype;
602
603     hr = get_value( view->table, row, column, &val );
604     if (hr != S_OK) return hr;
605
606     switch (view->table->columns[column].type & COL_TYPE_MASK)
607     {
608     case CIM_BOOLEAN:
609         if (!vartype) vartype = VT_BOOL;
610         break;
611     case CIM_STRING:
612     case CIM_DATETIME:
613         if (val)
614         {
615             vartype = VT_BSTR;
616             val_bstr = SysAllocString( (const WCHAR *)(INT_PTR)val );
617         }
618         else
619             vartype = VT_NULL;
620         break;
621     case CIM_SINT16:
622         if (!vartype) vartype = VT_I2;
623         break;
624     case CIM_UINT16:
625         if (!vartype) vartype = VT_UI2;
626         break;
627     case CIM_SINT32:
628         if (!vartype) vartype = VT_I4;
629         break;
630     case CIM_UINT32:
631         if (!vartype) vartype = VT_UI4;
632         break;
633     case CIM_SINT64:
634         vartype = VT_BSTR;
635         val_bstr = get_value_bstr( view->table, row, column );
636         break;
637     case CIM_UINT64:
638         vartype = VT_BSTR;
639         val_bstr = get_value_bstr( view->table, row, column );
640         break;
641     default:
642         ERR("unhandled column type %u\n", view->table->columns[column].type);
643         return WBEM_E_FAILED;
644     }
645     set_variant( vartype, val, val_bstr, ret );
646     if (type) *type = view->table->columns[column].type & COL_TYPE_MASK;
647     if (flavor) *flavor = 0;
648     return S_OK;
649 }
650
651 static HRESULT variant_to_longlong( VARIANT *var, LONGLONG *val, CIMTYPE *type )
652 {
653     if (!var)
654     {
655         *val = 0;
656         return S_OK;
657     }
658     switch (V_VT( var ))
659     {
660     case VT_BOOL:
661         *val = V_BOOL( var );
662         *type = CIM_BOOLEAN;
663         break;
664     case VT_BSTR:
665         *val = (INT_PTR)SysAllocString( V_BSTR( var ) );
666         if (!*val) return E_OUTOFMEMORY;
667         *type = CIM_STRING;
668         break;
669     case VT_I2:
670         *val = V_I2( var );
671         *type = CIM_SINT16;
672         break;
673     case VT_UI2:
674         *val = V_UI2( var );
675         *type = CIM_UINT16;
676         break;
677     case VT_I4:
678         *val = V_I4( var );
679         *type = CIM_SINT32;
680         break;
681     case VT_UI4:
682         *val = V_UI4( var );
683         *type = CIM_UINT32;
684         break;
685     case VT_NULL:
686         *val = 0;
687         break;
688     default:
689         ERR("unhandled type %u\n", V_VT( var ));
690         return WBEM_E_FAILED;
691     }
692     return S_OK;
693 }
694
695 HRESULT put_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *var, CIMTYPE type )
696 {
697     HRESULT hr;
698     UINT column, row = view->result[index];
699     LONGLONG val;
700
701     hr = get_column_index( view->table, name, &column );
702     if (hr != S_OK)
703     {
704         FIXME("no support for creating new properties\n");
705         return WBEM_E_FAILED;
706     }
707     if (is_method( view->table, column ) || !(view->table->columns[column].type & COL_FLAG_DYNAMIC))
708         return WBEM_E_FAILED;
709
710     hr = variant_to_longlong( var, &val, &type );
711     if (hr != S_OK) return hr;
712
713     return set_value( view->table, row, column, val, type );
714 }
715
716 HRESULT get_properties( const struct view *view, SAFEARRAY **props )
717 {
718     SAFEARRAY *sa;
719     BSTR str;
720     LONG i;
721     UINT num_props = count_properties( view );
722
723     if (!(sa = SafeArrayCreateVector( VT_BSTR, 0, num_props ))) return E_OUTOFMEMORY;
724
725     for (i = 0; i < view->table->num_cols; i++)
726     {
727         if (is_method( view->table, i )) continue;
728
729         str = SysAllocString( view->table->columns[i].name );
730         if (!str || SafeArrayPutElement( sa, &i, str ) != S_OK)
731         {
732             SysFreeString( str );
733             SafeArrayDestroy( sa );
734             return E_OUTOFMEMORY;
735         }
736     }
737     *props = sa;
738     return S_OK;
739 }