wbemprox: Implement IWbemClassObject::Put.
[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_BSTR:
554         V_VT( ret ) = VT_BSTR;
555         V_BSTR( ret ) = val_bstr;
556         return;
557     case VT_I2:
558         V_VT( ret ) = VT_I2;
559         V_I2( ret ) = val;
560         return;
561     case VT_UI2:
562         V_VT( ret ) = VT_UI2;
563         V_UI2( ret ) = val;
564         return;
565     case VT_I4:
566         V_VT( ret ) = VT_I4;
567         V_I4( ret ) = val;
568         return;
569     case VT_UI4:
570         V_VT( ret ) = VT_UI4;
571         V_UI4( ret ) = val;
572         return;
573     case VT_NULL:
574         V_VT( ret ) = VT_NULL;
575         return;
576     default:
577         ERR("unhandled variant type %u\n", vartype);
578         return;
579     }
580 }
581
582 HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *ret,
583                      CIMTYPE *type, LONG *flavor )
584 {
585     HRESULT hr;
586     UINT column, row = view->result[index];
587     VARTYPE vartype;
588     BSTR val_bstr = NULL;
589     LONGLONG val;
590
591     if (is_system_prop( name )) return get_system_propval( view, index, name, ret, type, flavor );
592     if (!is_selected_prop( view, name )) return WBEM_E_NOT_FOUND;
593
594     hr = get_column_index( view->table, name, &column );
595     if (hr != S_OK || is_method( view->table, column )) return WBEM_E_NOT_FOUND;
596
597     vartype = view->table->columns[column].vartype;
598
599     hr = get_value( view->table, row, column, &val );
600     if (hr != S_OK) return hr;
601
602     switch (view->table->columns[column].type & COL_TYPE_MASK)
603     {
604     case CIM_STRING:
605     case CIM_DATETIME:
606         if (val)
607         {
608             vartype = VT_BSTR;
609             val_bstr = SysAllocString( (const WCHAR *)(INT_PTR)val );
610         }
611         else
612             vartype = VT_NULL;
613         break;
614     case CIM_SINT16:
615         if (!vartype) vartype = VT_I2;
616         break;
617     case CIM_UINT16:
618         if (!vartype) vartype = VT_UI2;
619         break;
620     case CIM_SINT32:
621         if (!vartype) vartype = VT_I4;
622         break;
623     case CIM_UINT32:
624         if (!vartype) vartype = VT_UI4;
625         break;
626     case CIM_SINT64:
627         vartype = VT_BSTR;
628         val_bstr = get_value_bstr( view->table, row, column );
629         break;
630     case CIM_UINT64:
631         vartype = VT_BSTR;
632         val_bstr = get_value_bstr( view->table, row, column );
633         break;
634     default:
635         ERR("unhandled column type %u\n", view->table->columns[column].type);
636         return WBEM_E_FAILED;
637     }
638     set_variant( vartype, val, val_bstr, ret );
639     if (type) *type = view->table->columns[column].type & COL_TYPE_MASK;
640     if (flavor) *flavor = 0;
641     return S_OK;
642 }
643
644 static HRESULT variant_to_longlong( VARIANT *var, LONGLONG *val, CIMTYPE *type )
645 {
646     if (!var)
647     {
648         *val = 0;
649         return S_OK;
650     }
651     switch (V_VT( var ))
652     {
653     case VT_BSTR:
654         *val = (INT_PTR)SysAllocString( V_BSTR( var ) );
655         if (!*val) return E_OUTOFMEMORY;
656         *type = CIM_STRING;
657         break;
658     case VT_I2:
659         *val = V_I2( var );
660         *type = CIM_SINT16;
661         break;
662     case VT_UI2:
663         *val = V_UI2( var );
664         *type = CIM_UINT16;
665         break;
666     case VT_I4:
667         *val = V_I4( var );
668         *type = CIM_SINT32;
669         break;
670     case VT_UI4:
671         *val = V_UI4( var );
672         *type = CIM_UINT32;
673         break;
674     case VT_NULL:
675         *val = 0;
676         break;
677     default:
678         ERR("unhandled type %u\n", V_VT( var ));
679         return WBEM_E_FAILED;
680     }
681     return S_OK;
682 }
683
684 HRESULT put_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *var, CIMTYPE type )
685 {
686     HRESULT hr;
687     UINT column, row = view->result[index];
688     LONGLONG val;
689
690     hr = get_column_index( view->table, name, &column );
691     if (hr != S_OK)
692     {
693         FIXME("no support for creating new properties\n");
694         return WBEM_E_FAILED;
695     }
696     if (is_method( view->table, column ) || !(view->table->columns[column].type & COL_FLAG_DYNAMIC))
697         return WBEM_E_FAILED;
698
699     hr = variant_to_longlong( var, &val, &type );
700     if (hr != S_OK) return hr;
701
702     return set_value( view->table, row, column, val, type );
703 }
704
705 HRESULT get_properties( const struct view *view, SAFEARRAY **props )
706 {
707     SAFEARRAY *sa;
708     BSTR str;
709     LONG i;
710     UINT num_props = count_properties( view );
711
712     if (!(sa = SafeArrayCreateVector( VT_BSTR, 0, num_props ))) return E_OUTOFMEMORY;
713
714     for (i = 0; i < view->table->num_cols; i++)
715     {
716         if (is_method( view->table, i )) continue;
717
718         str = SysAllocString( view->table->columns[i].name );
719         if (!str || SafeArrayPutElement( sa, &i, str ) != S_OK)
720         {
721             SysFreeString( str );
722             SafeArrayDestroy( sa );
723             return E_OUTOFMEMORY;
724         }
725     }
726     *props = sa;
727     return S_OK;
728 }