mshtml: Keep reference in node returned from get_node.
[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 static HRESULT get_column_index( const struct table *table, const WCHAR *name, UINT *column )
34 {
35     UINT i;
36     for (i = 0; i < table->num_cols; i++)
37     {
38         if (!strcmpiW( table->columns[i].name, name ))
39         {
40             *column = i;
41             return S_OK;
42         }
43     }
44     return WBEM_E_INVALID_QUERY;
45 }
46
47 static UINT get_column_size( const struct table *table, UINT column )
48 {
49     if (table->columns[column].type & CIM_FLAG_ARRAY) return sizeof(void *);
50
51     switch (table->columns[column].type & COL_TYPE_MASK)
52     {
53     case CIM_SINT16:
54     case CIM_UINT16:
55         return sizeof(INT16);
56     case CIM_SINT32:
57     case CIM_UINT32:
58         return sizeof(INT32);
59     case CIM_DATETIME:
60     case CIM_STRING:
61         return sizeof(WCHAR *);
62     default:
63         ERR("unkown column type %u\n", table->columns[column].type & COL_TYPE_MASK);
64         break;
65     }
66     return sizeof(INT32);
67 }
68
69 static UINT get_column_offset( const struct table *table, UINT column )
70 {
71     UINT i, offset = 0;
72     for (i = 0; i < column; i++) offset += get_column_size( table, i );
73     return offset;
74 }
75
76 static UINT get_row_size( const struct table *table )
77 {
78     return get_column_offset( table, table->num_cols - 1 ) + get_column_size( table, table->num_cols - 1 );
79 }
80
81 static HRESULT get_value( const struct table *table, UINT row, UINT column, INT_PTR *val )
82 {
83     UINT col_offset, row_size;
84     const BYTE *ptr;
85
86     col_offset = get_column_offset( table, column );
87     row_size = get_row_size( table );
88     ptr = table->data + row * row_size + col_offset;
89
90     if (table->columns[column].type & CIM_FLAG_ARRAY)
91     {
92         *val = (INT_PTR)*(const void **)ptr;
93         return S_OK;
94     }
95     switch (table->columns[column].type & COL_TYPE_MASK)
96     {
97     case CIM_DATETIME:
98     case CIM_STRING:
99         *val = (INT_PTR)*(const WCHAR **)ptr;
100         break;
101     case CIM_SINT16:
102         *val = *(const INT16 *)ptr;
103         break;
104     case CIM_UINT16:
105         *val = *(const UINT16 *)ptr;
106         break;
107     case CIM_SINT32:
108         *val = *(const INT32 *)ptr;
109         break;
110     case CIM_UINT32:
111         *val = *(const UINT32 *)ptr;
112         break;
113     default:
114         ERR("invalid column type %u\n", table->columns[column].type & COL_TYPE_MASK);
115         *val = 0;
116         break;
117     }
118     return S_OK;
119 }
120
121 static BSTR get_value_bstr( const struct table *table, UINT row, UINT column )
122 {
123     static const WCHAR fmt_signedW[] = {'%','d',0};
124     static const WCHAR fmt_unsignedW[] = {'%','u',0};
125     static const WCHAR fmt_strW[] = {'\"','%','s','\"',0};
126     INT_PTR val;
127     BSTR ret;
128     WCHAR number[12];
129     UINT len;
130
131     if (table->columns[column].type & CIM_FLAG_ARRAY)
132     {
133         FIXME("array to string conversion not handled\n");
134         return NULL;
135     }
136     if (get_value( table, row, column, &val ) != S_OK) return NULL;
137
138     switch (table->columns[column].type & COL_TYPE_MASK)
139     {
140     case CIM_DATETIME:
141     case CIM_STRING:
142         len = strlenW( (const WCHAR *)val ) + 2;
143         if (!(ret = SysAllocStringLen( NULL, len ))) return NULL;
144         sprintfW( ret, fmt_strW, (const WCHAR *)val );
145         return ret;
146
147     case CIM_SINT16:
148     case CIM_SINT32:
149         sprintfW( number, fmt_signedW, val );
150         return SysAllocString( number );
151
152     case CIM_UINT16:
153     case CIM_UINT32:
154         sprintfW( number, fmt_unsignedW, val );
155         return SysAllocString( number );
156
157     default:
158         FIXME("unhandled column type %u\n", table->columns[column].type & COL_TYPE_MASK);
159         break;
160     }
161     return NULL;
162 }
163
164 HRESULT create_view( const struct property *proplist, const WCHAR *class,
165                      const struct expr *cond, struct view **ret )
166 {
167     struct view *view = heap_alloc( sizeof(struct view) );
168
169     if (!view) return E_OUTOFMEMORY;
170     view->proplist = proplist;
171     view->table    = get_table( class );
172     view->cond     = cond;
173     view->result   = NULL;
174     view->count    = 0;
175     view->index    = 0;
176     *ret = view;
177     return S_OK;
178 }
179
180 static void clear_table( struct table *table )
181 {
182     UINT i, j, type;
183
184     if (!table->fill || !table->data) return;
185
186     for (i = 0; i < table->num_rows; i++)
187     {
188         for (j = 0; j < table->num_cols; j++)
189         {
190             if (!(table->columns[j].type & COL_FLAG_DYNAMIC)) continue;
191
192             type = table->columns[j].type & COL_TYPE_MASK;
193             if (type == CIM_STRING || type == CIM_DATETIME || (type & CIM_FLAG_ARRAY))
194             {
195                 void *ptr;
196                 if (get_value( table, i, j, (INT_PTR *)&ptr ) == S_OK) heap_free( ptr );
197             }
198         }
199     }
200     heap_free( table->data );
201     table->data = NULL;
202 }
203
204 void destroy_view( struct view *view )
205 {
206     if (view->table) clear_table( view->table );
207     heap_free( view->result );
208     heap_free( view );
209 }
210
211 static BOOL eval_like( INT_PTR lval, INT_PTR rval )
212 {
213     const WCHAR *p = (const WCHAR *)lval, *q = (const WCHAR *)rval;
214
215     while (*p && *q)
216     {
217         if (*q == '%')
218         {
219             while (*q == '%') q++;
220             if (!*q) return TRUE;
221             while (*p && toupperW( p[1] ) != toupperW( q[1] )) p++;
222             if (!*p) return TRUE;
223         }
224         if (toupperW( *p++ ) != toupperW( *q++ )) return FALSE;
225     }
226     return TRUE;
227 }
228
229 static HRESULT eval_cond( const struct table *, UINT, const struct expr *, INT_PTR * );
230
231 static BOOL eval_binary( const struct table *table, UINT row, const struct complex_expr *expr,
232                          INT_PTR *val )
233 {
234     HRESULT lret, rret;
235     INT_PTR lval, rval;
236
237     lret = eval_cond( table, row, expr->left, &lval );
238     rret = eval_cond( table, row, expr->right, &rval );
239     if (lret != S_OK || rret != S_OK) return WBEM_E_INVALID_QUERY;
240
241     switch (expr->op)
242     {
243     case OP_EQ:
244         *val = (lval == rval);
245         break;
246     case OP_AND:
247         *val = (lval && rval);
248         break;
249     case OP_OR:
250         *val = (lval || rval);
251         break;
252     case OP_GT:
253         *val = (lval > rval);
254         break;
255     case OP_LT:
256         *val = (lval < rval);
257         break;
258     case OP_LE:
259         *val = (lval <= rval);
260         break;
261     case OP_GE:
262         *val = (lval >= rval);
263         break;
264     case OP_NE:
265         *val = (lval != rval);
266         break;
267     case OP_LIKE:
268         *val = eval_like( lval, rval );
269         break;
270     default:
271         ERR("unknown operator %u\n", expr->op);
272         return WBEM_E_INVALID_QUERY;
273     }
274     return S_OK;
275 }
276
277 static HRESULT eval_unary( const struct table *table, UINT row, const struct complex_expr *expr,
278                            INT_PTR *val )
279
280 {
281     HRESULT hr;
282     UINT column;
283     INT_PTR lval;
284
285     hr = get_column_index( table, expr->left->u.propval->name, &column );
286     if (hr != S_OK)
287         return hr;
288
289     hr = get_value( table, row, column, &lval );
290     if (hr != S_OK)
291         return hr;
292
293     switch (expr->op)
294     {
295     case OP_ISNULL:
296         *val = !lval;
297         break;
298     case OP_NOTNULL:
299         *val = lval;
300         break;
301     default:
302         ERR("unknown operator %u\n", expr->op);
303         return WBEM_E_INVALID_QUERY;
304     }
305     return S_OK;
306 }
307
308 static HRESULT eval_propval( const struct table *table, UINT row, const struct property *propval,
309                              INT_PTR *val )
310
311 {
312     HRESULT hr;
313     UINT column;
314
315     hr = get_column_index( table, propval->name, &column );
316     if (hr != S_OK)
317         return hr;
318
319     return get_value( table, row, column, val );
320 }
321
322 static HRESULT eval_cond( const struct table *table, UINT row, const struct expr *cond,
323                           INT_PTR *val )
324 {
325     if (!cond)
326     {
327         *val = 1;
328         return S_OK;
329     }
330     switch (cond->type)
331     {
332     case EXPR_COMPLEX:
333         return eval_binary( table, row, &cond->u.expr, val );
334     case EXPR_UNARY:
335         return eval_unary( table, row, &cond->u.expr, val );
336     case EXPR_PROPVAL:
337         return eval_propval( table, row, cond->u.propval, val );
338     case EXPR_SVAL:
339         *val = (INT_PTR)cond->u.sval;
340         return S_OK;
341     case EXPR_IVAL:
342     case EXPR_BVAL:
343         *val = cond->u.ival;
344         return S_OK;
345     default:
346         ERR("invalid expression type\n");
347         break;
348     }
349     return WBEM_E_INVALID_QUERY;
350 }
351
352 static HRESULT execute_view( struct view *view )
353 {
354     UINT i, j = 0, len;
355
356     if (!view->table || !view->table->num_rows) return S_OK;
357
358     len = min( view->table->num_rows, 16 );
359     if (!(view->result = heap_alloc( len * sizeof(UINT) ))) return E_OUTOFMEMORY;
360
361     for (i = 0; i < view->table->num_rows; i++)
362     {
363         HRESULT hr;
364         INT_PTR val = 0;
365
366         if (j >= len)
367         {
368             UINT *tmp;
369             len *= 2;
370             if (!(tmp = heap_realloc( view->result, len * sizeof(UINT) ))) return E_OUTOFMEMORY;
371             view->result = tmp;
372         }
373         if ((hr = eval_cond( view->table, i, view->cond, &val )) != S_OK) return hr;
374         if (val) view->result[j++] = i;
375     }
376     view->count = j;
377     return S_OK;
378 }
379
380 static struct query *alloc_query(void)
381 {
382     struct query *query;
383
384     if (!(query = heap_alloc( sizeof(*query) ))) return NULL;
385     list_init( &query->mem );
386     return query;
387 }
388
389 void free_query( struct query *query )
390 {
391     struct list *mem, *next;
392
393     destroy_view( query->view );
394     LIST_FOR_EACH_SAFE( mem, next, &query->mem )
395     {
396         heap_free( mem );
397     }
398     heap_free( query );
399 }
400
401 HRESULT exec_query( const WCHAR *str, IEnumWbemClassObject **result )
402 {
403     HRESULT hr;
404     struct query *query;
405
406     *result = NULL;
407     if (!(query = alloc_query())) return E_OUTOFMEMORY;
408     hr = parse_query( str, &query->view, &query->mem );
409     if (hr != S_OK) goto done;
410     hr = execute_view( query->view );
411     if (hr != S_OK) goto done;
412     hr = EnumWbemClassObject_create( NULL, query, (void **)result );
413
414 done:
415     if (hr != S_OK) free_query( query );
416     return hr;
417 }
418
419 static BOOL is_selected_prop( const struct view *view, const WCHAR *name )
420 {
421     const struct property *prop = view->proplist;
422
423     if (!prop) return TRUE;
424     while (prop)
425     {
426         if (!strcmpiW( prop->name, name )) return TRUE;
427         prop = prop->next;
428     }
429     return FALSE;
430 }
431
432 static BOOL is_system_prop( const WCHAR *name )
433 {
434     return (name[0] == '_' && name[1] == '_');
435 }
436
437 static BSTR build_servername( const struct view *view )
438 {
439     WCHAR server[MAX_COMPUTERNAME_LENGTH + 1], *p;
440     DWORD len = sizeof(server)/sizeof(server[0]);
441
442     if (view->proplist) return NULL;
443
444     if (!(GetComputerNameW( server, &len ))) return NULL;
445     for (p = server; *p; p++) *p = toupperW( *p );
446     return SysAllocString( server );
447 }
448
449 static BSTR build_classname( const struct view *view )
450 {
451     return SysAllocString( view->table->name );
452 }
453
454 static BSTR build_namespace( const struct view *view )
455 {
456     static const WCHAR cimv2W[] = {'R','O','O','T','\\','C','I','M','V','2',0};
457
458     if (view->proplist) return NULL;
459     return SysAllocString( cimv2W );
460 }
461
462 static BSTR build_proplist( const struct view *view, UINT index, UINT count, UINT *len )
463 {
464     static const WCHAR fmtW[] = {'%','s','=','%','s',0};
465     UINT i, j, offset, row = view->result[index];
466     BSTR *values, ret = NULL;
467
468     if (!(values = heap_alloc( count * sizeof(BSTR) ))) return NULL;
469
470     *len = j = 0;
471     for (i = 0; i < view->table->num_cols; i++)
472     {
473         if (view->table->columns[i].type & COL_FLAG_KEY)
474         {
475             const WCHAR *name = view->table->columns[i].name;
476
477             values[j] = get_value_bstr( view->table, row, i );
478             *len += strlenW( fmtW ) + strlenW( name ) + strlenW( values[j] );
479             j++;
480         }
481     }
482     if ((ret = SysAllocStringLen( NULL, *len )))
483     {
484         offset = j = 0;
485         for (i = 0; i < view->table->num_cols; i++)
486         {
487             if (view->table->columns[i].type & COL_FLAG_KEY)
488             {
489                 const WCHAR *name = view->table->columns[i].name;
490
491                 offset += sprintfW( ret + offset, fmtW, name, values[j] );
492                 if (j < count - 1) ret[offset++] = ',';
493                 j++;
494             }
495         }
496     }
497     for (i = 0; i < count; i++) SysFreeString( values[i] );
498     heap_free( values );
499     return ret;
500 }
501
502 static UINT count_key_columns( const struct view *view )
503 {
504     UINT i, num_keys = 0;
505
506     for (i = 0; i < view->table->num_cols; i++)
507     {
508         if (view->table->columns[i].type & COL_FLAG_KEY) num_keys++;
509     }
510     return num_keys;
511 }
512
513 static BSTR build_relpath( const struct view *view, UINT index, const WCHAR *name )
514 {
515     static const WCHAR fmtW[] = {'%','s','.','%','s',0};
516     BSTR class, proplist, ret = NULL;
517     UINT num_keys, len;
518
519     if (view->proplist) return NULL;
520
521     if (!(class = build_classname( view ))) return NULL;
522     if (!(num_keys = count_key_columns( view ))) return class;
523     if (!(proplist = build_proplist( view, index, num_keys, &len ))) goto done;
524
525     len += strlenW( fmtW ) + SysStringLen( class );
526     if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
527     sprintfW( ret, fmtW, class, proplist );
528
529 done:
530     SysFreeString( class );
531     SysFreeString( proplist );
532     return ret;
533 }
534
535 static BSTR build_path( const struct view *view, UINT index, const WCHAR *name )
536 {
537     static const WCHAR fmtW[] = {'\\','\\','%','s','\\','%','s',':','%','s',0};
538     BSTR server, namespace = NULL, relpath = NULL, ret = NULL;
539     UINT len;
540
541     if (view->proplist) return NULL;
542
543     if (!(server = build_servername( view ))) return NULL;
544     if (!(namespace = build_namespace( view ))) goto done;
545     if (!(relpath = build_relpath( view, index, name ))) goto done;
546
547     len = strlenW( fmtW ) + SysStringLen( server ) + SysStringLen( namespace ) + SysStringLen( relpath );
548     if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
549     sprintfW( ret, fmtW, server, namespace, relpath );
550
551 done:
552     SysFreeString( server );
553     SysFreeString( namespace );
554     SysFreeString( relpath );
555     return ret;
556 }
557
558 static UINT count_selected_props( const struct view *view )
559 {
560     const struct property *prop = view->proplist;
561     UINT count;
562
563     if (!prop) return view->table->num_cols;
564
565     count = 1;
566     while ((prop = prop->next)) count++;
567     return count;
568 }
569
570 static HRESULT get_system_propval( const struct view *view, UINT index, const WCHAR *name,
571                                    VARIANT *ret, CIMTYPE *type )
572 {
573     static const WCHAR classW[] = {'_','_','C','L','A','S','S',0};
574     static const WCHAR genusW[] = {'_','_','G','E','N','U','S',0};
575     static const WCHAR pathW[] = {'_','_','P','A','T','H',0};
576     static const WCHAR namespaceW[] = {'_','_','N','A','M','E','S','P','A','C','E',0};
577     static const WCHAR propcountW[] = {'_','_','P','R','O','P','E','R','T','Y','_','C','O','U','N','T',0};
578     static const WCHAR relpathW[] = {'_','_','R','E','L','P','A','T','H',0};
579     static const WCHAR serverW[] = {'_','_','S','E','R','V','E','R',0};
580
581     if (!strcmpiW( name, classW ))
582     {
583         V_VT( ret ) = VT_BSTR;
584         V_BSTR( ret ) = build_classname( view );
585         if (type) *type = CIM_STRING;
586         return S_OK;
587     }
588     if (!strcmpiW( name, genusW ))
589     {
590         V_VT( ret ) = VT_INT;
591         V_INT( ret ) = WBEM_GENUS_INSTANCE; /* FIXME */
592         if (type) *type = CIM_SINT32;
593         return S_OK;
594     }
595     else if (!strcmpiW( name, namespaceW ))
596     {
597         V_VT( ret ) = VT_BSTR;
598         V_BSTR( ret ) = build_namespace( view );
599         if (type) *type = CIM_STRING;
600         return S_OK;
601     }
602     else if (!strcmpiW( name, pathW ))
603     {
604         V_VT( ret ) = VT_BSTR;
605         V_BSTR( ret ) = build_path( view, index, name );
606         if (type) *type = CIM_STRING;
607         return S_OK;
608     }
609     if (!strcmpiW( name, propcountW ))
610     {
611         V_VT( ret ) = VT_INT;
612         V_INT( ret ) = count_selected_props( view );
613         if (type) *type = CIM_SINT32;
614         return S_OK;
615     }
616     else if (!strcmpiW( name, relpathW ))
617     {
618         V_VT( ret ) = VT_BSTR;
619         V_BSTR( ret ) = build_relpath( view, index, name );
620         if (type) *type = CIM_STRING;
621         return S_OK;
622     }
623     else if (!strcmpiW( name, serverW ))
624     {
625         V_VT( ret ) = VT_BSTR;
626         V_BSTR( ret ) = build_servername( view );
627         if (type) *type = CIM_STRING;
628         return S_OK;
629     }
630     FIXME("system property %s not implemented\n", debugstr_w(name));
631     return WBEM_E_NOT_FOUND;
632 }
633
634 HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *ret, CIMTYPE *type )
635 {
636     HRESULT hr;
637     UINT column, row = view->result[index];
638     INT_PTR val;
639
640     if (is_system_prop( name )) return get_system_propval( view, index, name, ret, type );
641     if (!is_selected_prop( view, name )) return WBEM_E_NOT_FOUND;
642
643     hr = get_column_index( view->table, name, &column );
644     if (hr != S_OK) return WBEM_E_NOT_FOUND;
645
646     hr = get_value( view->table, row, column, &val );
647     if (hr != S_OK) return hr;
648
649     switch (view->table->columns[column].type & COL_TYPE_MASK)
650     {
651     case CIM_STRING:
652     case CIM_DATETIME:
653         V_VT( ret ) = VT_BSTR;
654         V_BSTR( ret ) = SysAllocString( (const WCHAR *)val );
655         break;
656     case CIM_SINT16:
657         V_VT( ret ) = VT_I2;
658         V_I2( ret ) = val;
659         break;
660     case CIM_UINT16:
661         V_VT( ret ) = VT_UI2;
662         V_UI2( ret ) = val;
663         break;
664     case CIM_SINT32:
665         V_VT( ret ) = VT_I4;
666         V_I4( ret ) = val;
667         break;
668     case CIM_UINT32:
669         V_VT( ret ) = VT_UI4;
670         V_UI4( ret ) = val;
671         break;
672     default:
673         ERR("unhandled column type %u\n", view->table->columns[column].type);
674         return WBEM_E_FAILED;
675     }
676     if (type) *type = view->table->columns[column].type & COL_TYPE_MASK;
677     return S_OK;
678 }
679
680 HRESULT get_properties( const struct view *view, SAFEARRAY **props )
681 {
682     SAFEARRAY *sa;
683     BSTR str;
684     LONG i;
685
686     if (!(sa = SafeArrayCreateVector( VT_BSTR, 0, view->table->num_cols ))) return E_OUTOFMEMORY;
687
688     for (i = 0; i < view->table->num_cols; i++)
689     {
690         str = SysAllocString( view->table->columns[i].name );
691         if (!str || SafeArrayPutElement( sa, &i, str ) != S_OK)
692         {
693             SysFreeString( str );
694             SafeArrayDestroy( sa );
695             return E_OUTOFMEMORY;
696         }
697     }
698     *props = sa;
699     return S_OK;
700 }