jscript: Use num_set_int where possible.
[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 HRESULT create_view( const struct property *proplist, const WCHAR *class,
122                      const struct expr *cond, struct view **ret )
123 {
124     struct view *view = heap_alloc( sizeof(struct view) );
125
126     if (!view) return E_OUTOFMEMORY;
127     view->proplist = proplist;
128     view->table    = get_table( class );
129     view->cond     = cond;
130     view->result   = NULL;
131     view->count    = 0;
132     view->index    = 0;
133     *ret = view;
134     return S_OK;
135 }
136
137 static void clear_table( struct table *table )
138 {
139     UINT i, j, type;
140
141     if (!table->fill || !table->data) return;
142
143     for (i = 0; i < table->num_rows; i++)
144     {
145         for (j = 0; j < table->num_cols; j++)
146         {
147             if (!(table->columns[j].type & COL_FLAG_DYNAMIC)) continue;
148
149             type = table->columns[j].type & COL_TYPE_MASK;
150             if (type == CIM_STRING || type == CIM_DATETIME || (type & CIM_FLAG_ARRAY))
151             {
152                 void *ptr;
153                 if (get_value( table, i, j, (INT_PTR *)&ptr ) == S_OK) heap_free( ptr );
154             }
155         }
156     }
157     heap_free( table->data );
158     table->data = NULL;
159 }
160
161 void destroy_view( struct view *view )
162 {
163     if (view->table) clear_table( view->table );
164     heap_free( view->result );
165     heap_free( view );
166 }
167
168 static BOOL eval_like( INT_PTR lval, INT_PTR rval )
169 {
170     const WCHAR *p = (const WCHAR *)lval, *q = (const WCHAR *)rval;
171
172     while (*p && *q)
173     {
174         if (*q == '%')
175         {
176             while (*q == '%') q++;
177             if (!*q) return TRUE;
178             while (*p && toupperW( p[1] ) != toupperW( q[1] )) p++;
179             if (!*p) return TRUE;
180         }
181         if (toupperW( *p++ ) != toupperW( *q++ )) return FALSE;
182     }
183     return TRUE;
184 }
185
186 static HRESULT eval_cond( const struct table *, UINT, const struct expr *, INT_PTR * );
187
188 static BOOL eval_binary( const struct table *table, UINT row, const struct complex_expr *expr,
189                          INT_PTR *val )
190 {
191     HRESULT lret, rret;
192     INT_PTR lval, rval;
193
194     lret = eval_cond( table, row, expr->left, &lval );
195     rret = eval_cond( table, row, expr->right, &rval );
196     if (lret != S_OK || rret != S_OK) return WBEM_E_INVALID_QUERY;
197
198     switch (expr->op)
199     {
200     case OP_EQ:
201         *val = (lval == rval);
202         break;
203     case OP_AND:
204         *val = (lval && rval);
205         break;
206     case OP_OR:
207         *val = (lval || rval);
208         break;
209     case OP_GT:
210         *val = (lval > rval);
211         break;
212     case OP_LT:
213         *val = (lval < rval);
214         break;
215     case OP_LE:
216         *val = (lval <= rval);
217         break;
218     case OP_GE:
219         *val = (lval >= rval);
220         break;
221     case OP_NE:
222         *val = (lval != rval);
223         break;
224     case OP_LIKE:
225         *val = eval_like( lval, rval );
226         break;
227     default:
228         ERR("unknown operator %u\n", expr->op);
229         return WBEM_E_INVALID_QUERY;
230     }
231     return S_OK;
232 }
233
234 static HRESULT eval_unary( const struct table *table, UINT row, const struct complex_expr *expr,
235                            INT_PTR *val )
236
237 {
238     HRESULT hr;
239     UINT column;
240     INT_PTR lval;
241
242     hr = get_column_index( table, expr->left->u.propval->name, &column );
243     if (hr != S_OK)
244         return hr;
245
246     hr = get_value( table, row, column, &lval );
247     if (hr != S_OK)
248         return hr;
249
250     switch (expr->op)
251     {
252     case OP_ISNULL:
253         *val = !lval;
254         break;
255     case OP_NOTNULL:
256         *val = lval;
257         break;
258     default:
259         ERR("unknown operator %u\n", expr->op);
260         return WBEM_E_INVALID_QUERY;
261     }
262     return S_OK;
263 }
264
265 static HRESULT eval_propval( const struct table *table, UINT row, const struct property *propval,
266                              INT_PTR *val )
267
268 {
269     HRESULT hr;
270     UINT column;
271
272     hr = get_column_index( table, propval->name, &column );
273     if (hr != S_OK)
274         return hr;
275
276     return get_value( table, row, column, val );
277 }
278
279 static HRESULT eval_cond( const struct table *table, UINT row, const struct expr *cond,
280                           INT_PTR *val )
281 {
282     if (!cond)
283     {
284         *val = 1;
285         return S_OK;
286     }
287     switch (cond->type)
288     {
289     case EXPR_COMPLEX:
290         return eval_binary( table, row, &cond->u.expr, val );
291     case EXPR_UNARY:
292         return eval_unary( table, row, &cond->u.expr, val );
293     case EXPR_PROPVAL:
294         return eval_propval( table, row, cond->u.propval, val );
295     case EXPR_SVAL:
296         *val = (INT_PTR)cond->u.sval;
297         return S_OK;
298     case EXPR_IVAL:
299     case EXPR_BVAL:
300         *val = cond->u.ival;
301         return S_OK;
302     default:
303         ERR("invalid expression type\n");
304         break;
305     }
306     return WBEM_E_INVALID_QUERY;
307 }
308
309 static HRESULT execute_view( struct view *view )
310 {
311     UINT i, j = 0, len;
312
313     if (!view->table || !view->table->num_rows) return S_OK;
314
315     len = min( view->table->num_rows, 16 );
316     if (!(view->result = heap_alloc( len * sizeof(UINT) ))) return E_OUTOFMEMORY;
317
318     for (i = 0; i < view->table->num_rows; i++)
319     {
320         HRESULT hr;
321         INT_PTR val = 0;
322
323         if (j >= len)
324         {
325             UINT *tmp;
326             len *= 2;
327             if (!(tmp = heap_realloc( view->result, len * sizeof(UINT) ))) return E_OUTOFMEMORY;
328             view->result = tmp;
329         }
330         if ((hr = eval_cond( view->table, i, view->cond, &val )) != S_OK) return hr;
331         if (val) view->result[j++] = i;
332     }
333     view->count = j;
334     return S_OK;
335 }
336
337 static struct query *alloc_query(void)
338 {
339     struct query *query;
340
341     if (!(query = heap_alloc( sizeof(*query) ))) return NULL;
342     list_init( &query->mem );
343     return query;
344 }
345
346 void free_query( struct query *query )
347 {
348     struct list *mem, *next;
349
350     destroy_view( query->view );
351     LIST_FOR_EACH_SAFE( mem, next, &query->mem )
352     {
353         heap_free( mem );
354     }
355     heap_free( query );
356 }
357
358 HRESULT exec_query( const WCHAR *str, IEnumWbemClassObject **result )
359 {
360     HRESULT hr;
361     struct query *query;
362
363     *result = NULL;
364     if (!(query = alloc_query())) return E_OUTOFMEMORY;
365     hr = parse_query( str, &query->view, &query->mem );
366     if (hr != S_OK) goto done;
367     hr = execute_view( query->view );
368     if (hr != S_OK) goto done;
369     hr = EnumWbemClassObject_create( NULL, query, (void **)result );
370
371 done:
372     if (hr != S_OK) free_query( query );
373     return hr;
374 }
375
376 static BOOL is_selected_prop( const struct view *view, const WCHAR *name )
377 {
378     const struct property *prop = view->proplist;
379
380     if (!prop) return TRUE;
381     while (prop)
382     {
383         if (!strcmpiW( prop->name, name )) return TRUE;
384         prop = prop->next;
385     }
386     return FALSE;
387 }
388
389 HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *ret, CIMTYPE *type )
390 {
391     HRESULT hr;
392     UINT column, row = view->result[index];
393     INT_PTR val;
394
395     if (!is_selected_prop( view, name )) return WBEM_E_NOT_FOUND;
396
397     hr = get_column_index( view->table, name, &column );
398     if (hr != S_OK) return WBEM_E_NOT_FOUND;
399
400     hr = get_value( view->table, row, column, &val );
401     if (hr != S_OK) return hr;
402
403     switch (view->table->columns[column].type & COL_TYPE_MASK)
404     {
405     case CIM_STRING:
406     case CIM_DATETIME:
407         V_VT( ret ) = VT_BSTR;
408         V_BSTR( ret ) = SysAllocString( (const WCHAR *)val );
409         break;
410     default:
411         ERR("unhandled column type %u\n", view->table->columns[column].type);
412         return WBEM_E_FAILED;
413     }
414     if (type) *type = view->table->columns[column].type & COL_TYPE_MASK;
415     return S_OK;
416 }
417
418 HRESULT get_properties( const struct view *view, SAFEARRAY **props )
419 {
420     SAFEARRAY *sa;
421     BSTR str;
422     LONG i;
423
424     if (!(sa = SafeArrayCreateVector( VT_BSTR, 0, view->table->num_cols ))) return E_OUTOFMEMORY;
425
426     for (i = 0; i < view->table->num_cols; i++)
427     {
428         str = SysAllocString( view->table->columns[i].name );
429         if (!str || SafeArrayPutElement( sa, &i, str ) != S_OK)
430         {
431             SysFreeString( str );
432             SafeArrayDestroy( sa );
433             return E_OUTOFMEMORY;
434         }
435     }
436     *props = sa;
437     return S_OK;
438 }