xref: /reactos/dll/win32/wbemprox/query.c (revision 8786e12d)
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    = grab_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     if (!view) return;
51     if (view->table) release_table( view->table );
52     heap_free( view->result );
53     heap_free( view );
54 }
55 
56 static BOOL eval_like( const WCHAR *lstr, const WCHAR *rstr )
57 {
58     const WCHAR *p = lstr, *q = rstr;
59 
60     while (*p && *q)
61     {
62         if (*q == '%')
63         {
64             while (*q == '%') q++;
65             if (!*q) return TRUE;
66             while (*p && *q && toupperW( *p ) == toupperW( *q )) { p++; q++; };
67             if (!*p && !*q) return TRUE;
68         }
69         if (*q != '%' && toupperW( *p++ ) != toupperW( *q++ )) return FALSE;
70     }
71     return TRUE;
72 }
73 
74 static HRESULT eval_strcmp( UINT op, const WCHAR *lstr, const WCHAR *rstr, LONGLONG *val )
75 {
76     if (!lstr || !rstr)
77     {
78         *val = 0;
79         return S_OK;
80     }
81     switch (op)
82     {
83     case OP_EQ:
84         *val = !strcmpW( lstr, rstr );
85         break;
86     case OP_GT:
87         *val = strcmpW( lstr, rstr ) > 0;
88         break;
89     case OP_LT:
90         *val = strcmpW( lstr, rstr ) < 0;
91         break;
92     case OP_LE:
93         *val = strcmpW( lstr, rstr ) <= 0;
94         break;
95     case OP_GE:
96         *val = strcmpW( lstr, rstr ) >= 0;
97         break;
98     case OP_NE:
99         *val = strcmpW( lstr, rstr );
100         break;
101     case OP_LIKE:
102         *val = eval_like( lstr, rstr );
103         break;
104     default:
105         ERR("unhandled operator %u\n", op);
106         return WBEM_E_INVALID_QUERY;
107     }
108     return S_OK;
109 }
110 
111 static BOOL is_int( CIMTYPE type )
112 {
113     switch (type)
114     {
115     case CIM_SINT8:
116     case CIM_SINT16:
117     case CIM_SINT32:
118     case CIM_SINT64:
119     case CIM_UINT8:
120     case CIM_UINT16:
121     case CIM_UINT32:
122     case CIM_UINT64:
123         return TRUE;
124     default:
125         return FALSE;
126     }
127 }
128 
129 static inline BOOL is_strcmp( const struct complex_expr *expr, UINT ltype, UINT rtype )
130 {
131     if ((ltype == CIM_STRING || is_int( ltype )) && expr->left->type == EXPR_PROPVAL &&
132         expr->right->type == EXPR_SVAL) return TRUE;
133     else if ((rtype == CIM_STRING || is_int( rtype )) && expr->right->type == EXPR_PROPVAL &&
134              expr->left->type == EXPR_SVAL) return TRUE;
135     return FALSE;
136 }
137 
138 static inline BOOL is_boolcmp( const struct complex_expr *expr, UINT ltype, UINT rtype )
139 {
140     if (ltype == CIM_BOOLEAN && expr->left->type == EXPR_PROPVAL &&
141         (expr->right->type == EXPR_SVAL || expr->right->type == EXPR_BVAL)) return TRUE;
142     else if (rtype == CIM_BOOLEAN && expr->right->type == EXPR_PROPVAL &&
143              (expr->left->type == EXPR_SVAL || expr->left->type == EXPR_BVAL)) return TRUE;
144     return FALSE;
145 }
146 
147 static HRESULT eval_boolcmp( UINT op, LONGLONG lval, LONGLONG rval, UINT ltype, UINT rtype, LONGLONG *val )
148 {
149     static const WCHAR trueW[] = {'T','r','u','e',0};
150 
151     if (ltype == CIM_STRING) lval = !strcmpiW( (const WCHAR *)(INT_PTR)lval, trueW ) ? -1 : 0;
152     else if (rtype == CIM_STRING) rval = !strcmpiW( (const WCHAR *)(INT_PTR)rval, trueW ) ? -1 : 0;
153 
154     switch (op)
155     {
156     case OP_EQ:
157         *val = (lval == rval);
158         break;
159     case OP_NE:
160         *val = (lval != rval);
161         break;
162     default:
163         ERR("unhandled operator %u\n", op);
164         return WBEM_E_INVALID_QUERY;
165     }
166     return S_OK;
167 }
168 
169 static UINT resolve_type( UINT left, UINT right )
170 {
171     switch (left)
172     {
173     case CIM_SINT8:
174     case CIM_SINT16:
175     case CIM_SINT32:
176     case CIM_SINT64:
177     case CIM_UINT8:
178     case CIM_UINT16:
179     case CIM_UINT32:
180     case CIM_UINT64:
181         switch (right)
182         {
183             case CIM_SINT8:
184             case CIM_SINT16:
185             case CIM_SINT32:
186             case CIM_SINT64:
187             case CIM_UINT8:
188             case CIM_UINT16:
189             case CIM_UINT32:
190             case CIM_UINT64:
191                 return CIM_UINT64;
192             default: break;
193         }
194         break;
195 
196     case CIM_STRING:
197         if (right == CIM_STRING) return CIM_STRING;
198         break;
199 
200     case CIM_BOOLEAN:
201         if (right == CIM_BOOLEAN) return CIM_BOOLEAN;
202         break;
203 
204     default:
205         break;
206     }
207     return CIM_ILLEGAL;
208 }
209 
210 static const WCHAR *format_int( WCHAR *buf, CIMTYPE type, LONGLONG val )
211 {
212     static const WCHAR fmt_signedW[] = {'%','d',0};
213     static const WCHAR fmt_unsignedW[] = {'%','u',0};
214     static const WCHAR fmt_signed64W[] = {'%','I','6','4','d',0};
215     static const WCHAR fmt_unsigned64W[] = {'%','I','6','4','u',0};
216 
217     switch (type)
218     {
219     case CIM_SINT8:
220     case CIM_SINT16:
221     case CIM_SINT32:
222         sprintfW( buf, fmt_signedW, val );
223         return buf;
224 
225     case CIM_UINT8:
226     case CIM_UINT16:
227     case CIM_UINT32:
228         sprintfW( buf, fmt_unsignedW, val );
229         return buf;
230 
231     case CIM_SINT64:
232         wsprintfW( buf, fmt_signed64W, val );
233         return buf;
234 
235     case CIM_UINT64:
236         wsprintfW( buf, fmt_unsigned64W, val );
237         return buf;
238 
239     default:
240         ERR( "unhandled type %u\n", type );
241         return NULL;
242     }
243 }
244 
245 static HRESULT eval_binary( const struct table *table, UINT row, const struct complex_expr *expr,
246                             LONGLONG *val, UINT *type )
247 {
248     HRESULT lret, rret;
249     LONGLONG lval, rval;
250     UINT ltype, rtype;
251 
252     lret = eval_cond( table, row, expr->left, &lval, &ltype );
253     rret = eval_cond( table, row, expr->right, &rval, &rtype );
254     if (lret != S_OK || rret != S_OK) return WBEM_E_INVALID_QUERY;
255 
256     *type = resolve_type( ltype, rtype );
257 
258     if (is_boolcmp( expr, ltype, rtype ))
259         return eval_boolcmp( expr->op, lval, rval, ltype, rtype, val );
260 
261     if (is_strcmp( expr, ltype, rtype ))
262     {
263         const WCHAR *lstr, *rstr;
264         WCHAR lbuf[21], rbuf[21];
265 
266         if (is_int( ltype )) lstr = format_int( lbuf, ltype, lval );
267         else lstr = (const WCHAR *)(INT_PTR)lval;
268 
269         if (is_int( rtype )) rstr = format_int( rbuf, rtype, rval );
270         else rstr = (const WCHAR *)(INT_PTR)rval;
271 
272         return eval_strcmp( expr->op, lstr, rstr, val );
273     }
274     switch (expr->op)
275     {
276     case OP_EQ:
277         *val = (lval == rval);
278         break;
279     case OP_AND:
280         *val = (lval && rval);
281         break;
282     case OP_OR:
283         *val = (lval || rval);
284         break;
285     case OP_GT:
286         *val = (lval > rval);
287         break;
288     case OP_LT:
289         *val = (lval < rval);
290         break;
291     case OP_LE:
292         *val = (lval <= rval);
293         break;
294     case OP_GE:
295         *val = (lval >= rval);
296         break;
297     case OP_NE:
298         *val = (lval != rval);
299         break;
300     default:
301         ERR("unhandled operator %u\n", expr->op);
302         return WBEM_E_INVALID_QUERY;
303     }
304     return S_OK;
305 }
306 
307 static HRESULT eval_unary( const struct table *table, UINT row, const struct complex_expr *expr,
308                            LONGLONG *val, UINT *type )
309 
310 {
311     HRESULT hr;
312     UINT column;
313     LONGLONG lval;
314 
315     if (expr->op == OP_NOT)
316     {
317         hr = eval_cond( table, row, expr->left, &lval, type );
318         if (hr != S_OK)
319             return hr;
320         *val = !lval;
321         return S_OK;
322     }
323 
324     hr = get_column_index( table, expr->left->u.propval->name, &column );
325     if (hr != S_OK)
326         return hr;
327 
328     hr = get_value( table, row, column, &lval );
329     if (hr != S_OK)
330         return hr;
331 
332     switch (expr->op)
333     {
334     case OP_ISNULL:
335         *val = !lval;
336         break;
337     case OP_NOTNULL:
338         *val = lval;
339         break;
340     default:
341         ERR("unknown operator %u\n", expr->op);
342         return WBEM_E_INVALID_QUERY;
343     }
344 
345     *type = table->columns[column].type & CIM_TYPE_MASK;
346     return S_OK;
347 }
348 
349 static HRESULT eval_propval( const struct table *table, UINT row, const struct property *propval,
350                              LONGLONG *val, UINT *type )
351 
352 {
353     HRESULT hr;
354     UINT column;
355 
356     hr = get_column_index( table, propval->name, &column );
357     if (hr != S_OK)
358         return hr;
359 
360     *type = table->columns[column].type & CIM_TYPE_MASK;
361     return get_value( table, row, column, val );
362 }
363 
364 HRESULT eval_cond( const struct table *table, UINT row, const struct expr *cond, LONGLONG *val, UINT *type )
365 {
366     if (!cond)
367     {
368         *val = 1;
369         *type = CIM_UINT64;
370         return S_OK;
371     }
372     switch (cond->type)
373     {
374     case EXPR_COMPLEX:
375         return eval_binary( table, row, &cond->u.expr, val, type );
376 
377     case EXPR_UNARY:
378         return eval_unary( table, row, &cond->u.expr, val, type );
379 
380     case EXPR_PROPVAL:
381         return eval_propval( table, row, cond->u.propval, val, type );
382 
383     case EXPR_SVAL:
384         *val = (INT_PTR)cond->u.sval;
385         *type = CIM_STRING;
386         return S_OK;
387 
388     case EXPR_IVAL:
389         *val = cond->u.ival;
390         *type = CIM_UINT64;
391         return S_OK;
392 
393     case EXPR_BVAL:
394         *val = cond->u.ival;
395         *type = CIM_BOOLEAN;
396         return S_OK;
397 
398     default:
399         ERR("invalid expression type\n");
400         break;
401     }
402     return WBEM_E_INVALID_QUERY;
403 }
404 
405 HRESULT execute_view( struct view *view )
406 {
407     UINT i, j = 0, len;
408 
409     if (!view->table) return S_OK;
410     if (view->table->fill)
411     {
412         clear_table( view->table );
413         view->table->fill( view->table, view->cond );
414     }
415     if (!view->table->num_rows) return S_OK;
416 
417     len = min( view->table->num_rows, 16 );
418     if (!(view->result = heap_alloc( len * sizeof(UINT) ))) return E_OUTOFMEMORY;
419 
420     for (i = 0; i < view->table->num_rows; i++)
421     {
422         HRESULT hr;
423         LONGLONG val = 0;
424         UINT type;
425 
426         if (j >= len)
427         {
428             UINT *tmp;
429             len *= 2;
430             if (!(tmp = heap_realloc( view->result, len * sizeof(UINT) ))) return E_OUTOFMEMORY;
431             view->result = tmp;
432         }
433         if ((hr = eval_cond( view->table, i, view->cond, &val, &type )) != S_OK) return hr;
434         if (val) view->result[j++] = i;
435     }
436     view->count = j;
437     return S_OK;
438 }
439 
440 struct query *create_query(void)
441 {
442     struct query *query;
443 
444     if (!(query = heap_alloc( sizeof(*query) ))) return NULL;
445     list_init( &query->mem );
446     query->refs = 1;
447     return query;
448 }
449 
450 void free_query( struct query *query )
451 {
452     struct list *mem, *next;
453 
454     if (!query) return;
455     destroy_view( query->view );
456     LIST_FOR_EACH_SAFE( mem, next, &query->mem ) { heap_free( mem ); }
457     heap_free( query );
458 }
459 
460 struct query *addref_query( struct query *query )
461 {
462     InterlockedIncrement( &query->refs );
463     return query;
464 }
465 
466 void release_query( struct query *query )
467 {
468     if (!InterlockedDecrement( &query->refs )) free_query( query );
469 }
470 
471 HRESULT exec_query( const WCHAR *str, IEnumWbemClassObject **result )
472 {
473     HRESULT hr;
474     struct query *query;
475 
476     *result = NULL;
477     if (!(query = create_query())) return E_OUTOFMEMORY;
478     hr = parse_query( str, &query->view, &query->mem );
479     if (hr != S_OK) goto done;
480     hr = execute_view( query->view );
481     if (hr != S_OK) goto done;
482     hr = EnumWbemClassObject_create( query, (void **)result );
483 
484 done:
485     release_query( query );
486     return hr;
487 }
488 
489 BOOL is_selected_prop( const struct view *view, const WCHAR *name )
490 {
491     const struct property *prop = view->proplist;
492 
493     if (!prop) return TRUE;
494     while (prop)
495     {
496         if (!strcmpiW( prop->name, name )) return TRUE;
497         prop = prop->next;
498     }
499     return FALSE;
500 }
501 
502 static BOOL is_system_prop( const WCHAR *name )
503 {
504     return (name[0] == '_' && name[1] == '_');
505 }
506 
507 static BSTR build_servername( const struct view *view )
508 {
509     WCHAR server[MAX_COMPUTERNAME_LENGTH + 1], *p;
510     DWORD len = sizeof(server)/sizeof(server[0]);
511 
512     if (view->proplist) return NULL;
513 
514     if (!(GetComputerNameW( server, &len ))) return NULL;
515     for (p = server; *p; p++) *p = toupperW( *p );
516     return SysAllocString( server );
517 }
518 
519 static BSTR build_classname( const struct view *view )
520 {
521     return SysAllocString( view->table->name );
522 }
523 
524 static BSTR build_namespace( const struct view *view )
525 {
526     static const WCHAR cimv2W[] = {'R','O','O','T','\\','C','I','M','V','2',0};
527 
528     if (view->proplist) return NULL;
529     return SysAllocString( cimv2W );
530 }
531 
532 static BSTR build_proplist( const struct view *view, UINT index, UINT count, UINT *len )
533 {
534     static const WCHAR fmtW[] = {'%','s','=','%','s',0};
535     UINT i, j, offset, row = view->result[index];
536     BSTR *values, ret = NULL;
537 
538     if (!(values = heap_alloc( count * sizeof(BSTR) ))) return NULL;
539 
540     *len = j = 0;
541     for (i = 0; i < view->table->num_cols; i++)
542     {
543         if (view->table->columns[i].type & COL_FLAG_KEY)
544         {
545             const WCHAR *name = view->table->columns[i].name;
546 
547             values[j] = get_value_bstr( view->table, row, i );
548             *len += strlenW( fmtW ) + strlenW( name ) + strlenW( values[j] );
549             j++;
550         }
551     }
552     if ((ret = SysAllocStringLen( NULL, *len )))
553     {
554         offset = j = 0;
555         for (i = 0; i < view->table->num_cols; i++)
556         {
557             if (view->table->columns[i].type & COL_FLAG_KEY)
558             {
559                 const WCHAR *name = view->table->columns[i].name;
560 
561                 offset += sprintfW( ret + offset, fmtW, name, values[j] );
562                 if (j < count - 1) ret[offset++] = ',';
563                 j++;
564             }
565         }
566     }
567     for (i = 0; i < count; i++) SysFreeString( values[i] );
568     heap_free( values );
569     return ret;
570 }
571 
572 static UINT count_key_columns( const struct view *view )
573 {
574     UINT i, num_keys = 0;
575 
576     for (i = 0; i < view->table->num_cols; i++)
577     {
578         if (view->table->columns[i].type & COL_FLAG_KEY) num_keys++;
579     }
580     return num_keys;
581 }
582 
583 static BSTR build_relpath( const struct view *view, UINT index, const WCHAR *name )
584 {
585     static const WCHAR fmtW[] = {'%','s','.','%','s',0};
586     BSTR class, proplist, ret = NULL;
587     UINT num_keys, len;
588 
589     if (view->proplist) return NULL;
590 
591     if (!(class = build_classname( view ))) return NULL;
592     if (!(num_keys = count_key_columns( view ))) return class;
593     if (!(proplist = build_proplist( view, index, num_keys, &len ))) goto done;
594 
595     len += strlenW( fmtW ) + SysStringLen( class );
596     if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
597     sprintfW( ret, fmtW, class, proplist );
598 
599 done:
600     SysFreeString( class );
601     SysFreeString( proplist );
602     return ret;
603 }
604 
605 static BSTR build_path( const struct view *view, UINT index, const WCHAR *name )
606 {
607     static const WCHAR fmtW[] = {'\\','\\','%','s','\\','%','s',':','%','s',0};
608     BSTR server, namespace = NULL, relpath = NULL, ret = NULL;
609     UINT len;
610 
611     if (view->proplist) return NULL;
612 
613     if (!(server = build_servername( view ))) return NULL;
614     if (!(namespace = build_namespace( view ))) goto done;
615     if (!(relpath = build_relpath( view, index, name ))) goto done;
616 
617     len = strlenW( fmtW ) + SysStringLen( server ) + SysStringLen( namespace ) + SysStringLen( relpath );
618     if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
619     sprintfW( ret, fmtW, server, namespace, relpath );
620 
621 done:
622     SysFreeString( server );
623     SysFreeString( namespace );
624     SysFreeString( relpath );
625     return ret;
626 }
627 
628 BOOL is_method( const struct table *table, UINT column )
629 {
630     return table->columns[column].type & COL_FLAG_METHOD;
631 }
632 
633 static UINT count_properties( const struct view *view )
634 {
635     UINT i, num_props = 0;
636 
637     for (i = 0; i < view->table->num_cols; i++)
638     {
639         if (!is_method( view->table, i)) num_props++;
640     }
641     return num_props;
642 }
643 
644 static UINT count_selected_properties( const struct view *view )
645 {
646     const struct property *prop = view->proplist;
647     UINT count;
648 
649     if (!prop) return count_properties( view );
650 
651     count = 1;
652     while ((prop = prop->next)) count++;
653     return count;
654 }
655 
656 static HRESULT get_system_propval( const struct view *view, UINT index, const WCHAR *name,
657                                    VARIANT *ret, CIMTYPE *type, LONG *flavor )
658 {
659     static const WCHAR classW[] = {'_','_','C','L','A','S','S',0};
660     static const WCHAR genusW[] = {'_','_','G','E','N','U','S',0};
661     static const WCHAR pathW[] = {'_','_','P','A','T','H',0};
662     static const WCHAR namespaceW[] = {'_','_','N','A','M','E','S','P','A','C','E',0};
663     static const WCHAR propcountW[] = {'_','_','P','R','O','P','E','R','T','Y','_','C','O','U','N','T',0};
664     static const WCHAR relpathW[] = {'_','_','R','E','L','P','A','T','H',0};
665     static const WCHAR serverW[] = {'_','_','S','E','R','V','E','R',0};
666 
667     if (flavor) *flavor = WBEM_FLAVOR_ORIGIN_SYSTEM;
668 
669     if (!strcmpiW( name, classW ))
670     {
671         V_VT( ret ) = VT_BSTR;
672         V_BSTR( ret ) = build_classname( view );
673         if (type) *type = CIM_STRING;
674         return S_OK;
675     }
676     if (!strcmpiW( name, genusW ))
677     {
678         V_VT( ret ) = VT_I4;
679         V_I4( ret ) = WBEM_GENUS_INSTANCE; /* FIXME */
680         if (type) *type = CIM_SINT32;
681         return S_OK;
682     }
683     else if (!strcmpiW( name, namespaceW ))
684     {
685         V_VT( ret ) = VT_BSTR;
686         V_BSTR( ret ) = build_namespace( view );
687         if (type) *type = CIM_STRING;
688         return S_OK;
689     }
690     else if (!strcmpiW( name, pathW ))
691     {
692         V_VT( ret ) = VT_BSTR;
693         V_BSTR( ret ) = build_path( view, index, name );
694         if (type) *type = CIM_STRING;
695         return S_OK;
696     }
697     if (!strcmpiW( name, propcountW ))
698     {
699         V_VT( ret ) = VT_I4;
700         V_I4( ret ) = count_selected_properties( view );
701         if (type) *type = CIM_SINT32;
702         return S_OK;
703     }
704     else if (!strcmpiW( name, relpathW ))
705     {
706         V_VT( ret ) = VT_BSTR;
707         V_BSTR( ret ) = build_relpath( view, index, name );
708         if (type) *type = CIM_STRING;
709         return S_OK;
710     }
711     else if (!strcmpiW( name, serverW ))
712     {
713         V_VT( ret ) = VT_BSTR;
714         V_BSTR( ret ) = build_servername( view );
715         if (type) *type = CIM_STRING;
716         return S_OK;
717     }
718     FIXME("system property %s not implemented\n", debugstr_w(name));
719     return WBEM_E_NOT_FOUND;
720 }
721 
722 VARTYPE to_vartype( CIMTYPE type )
723 {
724     switch (type)
725     {
726     case CIM_BOOLEAN:  return VT_BOOL;
727     case CIM_STRING:
728     case CIM_DATETIME: return VT_BSTR;
729     case CIM_SINT8:    return VT_I1;
730     case CIM_UINT8:    return VT_UI1;
731     case CIM_SINT16:   return VT_I2;
732     case CIM_UINT16:   return VT_UI2;
733     case CIM_SINT32:   return VT_I4;
734     case CIM_UINT32:   return VT_UI4;
735     case CIM_SINT64:   return VT_I8;
736     case CIM_UINT64:   return VT_UI8;
737     default:
738         ERR("unhandled type %u\n", type);
739         break;
740     }
741     return 0;
742 }
743 
744 SAFEARRAY *to_safearray( const struct array *array, CIMTYPE type )
745 {
746     SAFEARRAY *ret;
747     UINT size = get_type_size( type );
748     VARTYPE vartype = to_vartype( type );
749     LONG i;
750 
751     if (!array || !(ret = SafeArrayCreateVector( vartype, 0, array->count ))) return NULL;
752 
753     for (i = 0; i < array->count; i++)
754     {
755         void *ptr = (char *)array->ptr + i * size;
756         if (vartype == VT_BSTR)
757         {
758             BSTR str = SysAllocString( *(const WCHAR **)ptr );
759             if (!str || SafeArrayPutElement( ret, &i, str ) != S_OK)
760             {
761                 SysFreeString( str );
762                 SafeArrayDestroy( ret );
763                 return NULL;
764             }
765             SysFreeString( str );
766         }
767         else if (SafeArrayPutElement( ret, &i, ptr ) != S_OK)
768         {
769             SafeArrayDestroy( ret );
770             return NULL;
771         }
772     }
773     return ret;
774 }
775 
776 void set_variant( VARTYPE type, LONGLONG val, void *val_ptr, VARIANT *ret )
777 {
778     if (type & VT_ARRAY)
779     {
780         V_VT( ret ) = type;
781         V_ARRAY( ret ) = val_ptr;
782         return;
783     }
784     switch (type)
785     {
786     case VT_BOOL:
787         V_BOOL( ret ) = val;
788         break;
789     case VT_BSTR:
790         V_BSTR( ret ) = val_ptr;
791         break;
792     case VT_I1:
793         V_I1( ret ) = val;
794         break;
795     case VT_UI1:
796         V_UI1( ret ) = val;
797         break;
798     case VT_I2:
799         V_I2( ret ) = val;
800         break;
801     case VT_UI2:
802         V_UI2( ret ) = val;
803         break;
804     case VT_I4:
805         V_I4( ret ) = val;
806         break;
807     case VT_UI4:
808         V_UI4( ret ) = val;
809         break;
810     case VT_NULL:
811         break;
812     default:
813         ERR("unhandled variant type %u\n", type);
814         return;
815     }
816     V_VT( ret ) = type;
817 }
818 
819 HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *ret,
820                      CIMTYPE *type, LONG *flavor )
821 {
822     HRESULT hr;
823     UINT column, row;
824     VARTYPE vartype;
825     void *val_ptr = NULL;
826     LONGLONG val;
827 
828     if (is_system_prop( name )) return get_system_propval( view, index, name, ret, type, flavor );
829     if (!view->count || !is_selected_prop( view, name )) return WBEM_E_NOT_FOUND;
830 
831     hr = get_column_index( view->table, name, &column );
832     if (hr != S_OK || is_method( view->table, column )) return WBEM_E_NOT_FOUND;
833 
834     row = view->result[index];
835     hr = get_value( view->table, row, column, &val );
836     if (hr != S_OK) return hr;
837 
838     vartype = view->table->columns[column].vartype;
839     if (view->table->columns[column].type & CIM_FLAG_ARRAY)
840     {
841         CIMTYPE basetype = view->table->columns[column].type & CIM_TYPE_MASK;
842 
843         val_ptr = to_safearray( (const struct array *)(INT_PTR)val, basetype );
844         if (!val_ptr) vartype = VT_NULL;
845         else if (!vartype) vartype = to_vartype( basetype ) | VT_ARRAY;
846         goto done;
847     }
848     switch (view->table->columns[column].type & COL_TYPE_MASK)
849     {
850     case CIM_BOOLEAN:
851         if (!vartype) vartype = VT_BOOL;
852         break;
853     case CIM_STRING:
854     case CIM_DATETIME:
855         if (val)
856         {
857             vartype = VT_BSTR;
858             val_ptr = SysAllocString( (const WCHAR *)(INT_PTR)val );
859         }
860         else
861             vartype = VT_NULL;
862         break;
863     case CIM_SINT8:
864         if (!vartype) vartype = VT_I1;
865         break;
866     case CIM_UINT8:
867         if (!vartype) vartype = VT_UI1;
868         break;
869     case CIM_SINT16:
870         if (!vartype) vartype = VT_I2;
871         break;
872     case CIM_UINT16:
873         if (!vartype) vartype = VT_UI2;
874         break;
875     case CIM_SINT32:
876         if (!vartype) vartype = VT_I4;
877         break;
878     case CIM_UINT32:
879         if (!vartype) vartype = VT_UI4;
880         break;
881     case CIM_SINT64:
882         vartype = VT_BSTR;
883         val_ptr = get_value_bstr( view->table, row, column );
884         break;
885     case CIM_UINT64:
886         vartype = VT_BSTR;
887         val_ptr = get_value_bstr( view->table, row, column );
888         break;
889     default:
890         ERR("unhandled column type %u\n", view->table->columns[column].type);
891         return WBEM_E_FAILED;
892     }
893 
894 done:
895     set_variant( vartype, val, val_ptr, ret );
896     if (type) *type = view->table->columns[column].type & COL_TYPE_MASK;
897     if (flavor) *flavor = 0;
898     return S_OK;
899 }
900 
901 static CIMTYPE to_cimtype( VARTYPE type )
902 {
903     switch (type)
904     {
905     case VT_BOOL:  return CIM_BOOLEAN;
906     case VT_BSTR:  return CIM_STRING;
907     case VT_I1:    return CIM_SINT8;
908     case VT_UI1:   return CIM_UINT8;
909     case VT_I2:    return CIM_SINT16;
910     case VT_UI2:   return CIM_UINT16;
911     case VT_I4:    return CIM_SINT32;
912     case VT_UI4:   return CIM_UINT32;
913     case VT_I8:    return CIM_SINT64;
914     case VT_UI8:   return CIM_UINT64;
915     default:
916         ERR("unhandled type %u\n", type);
917         break;
918     }
919     return 0;
920 }
921 
922 static struct array *to_array( VARIANT *var, CIMTYPE *type )
923 {
924     struct array *ret;
925     LONG bound, i;
926     VARTYPE vartype;
927     CIMTYPE basetype;
928     UINT size;
929 
930     if (SafeArrayGetVartype( V_ARRAY( var ), &vartype ) != S_OK) return NULL;
931     if (!(basetype = to_cimtype( vartype ))) return NULL;
932     if (SafeArrayGetUBound( V_ARRAY( var ), 1, &bound ) != S_OK) return NULL;
933     if (!(ret = heap_alloc( sizeof(struct array) ))) return NULL;
934 
935     ret->count = bound + 1;
936     size = get_type_size( basetype );
937     if (!(ret->ptr = heap_alloc_zero( ret->count * size )))
938     {
939         heap_free( ret );
940         return NULL;
941     }
942     for (i = 0; i < ret->count; i++)
943     {
944         void *ptr = (char *)ret->ptr + i * size;
945         if (vartype == VT_BSTR)
946         {
947             BSTR str;
948             if (SafeArrayGetElement( V_ARRAY( var ), &i, &str ) != S_OK)
949             {
950                 destroy_array( ret, basetype );
951                 return NULL;
952             }
953             *(WCHAR **)ptr = heap_strdupW( str );
954             SysFreeString( str );
955             if (!*(WCHAR **)ptr)
956             {
957                 destroy_array( ret, basetype );
958                 return NULL;
959             }
960         }
961         else if (SafeArrayGetElement( V_ARRAY( var ), &i, ptr ) != S_OK)
962         {
963             destroy_array( ret, basetype );
964             return NULL;
965         }
966     }
967     *type = basetype | CIM_FLAG_ARRAY;
968     return ret;
969 }
970 
971 HRESULT to_longlong( VARIANT *var, LONGLONG *val, CIMTYPE *type )
972 {
973     if (!var)
974     {
975         *val = 0;
976         return S_OK;
977     }
978     if (V_VT( var ) & VT_ARRAY)
979     {
980         *val = (INT_PTR)to_array( var, type );
981         if (!*val) return E_OUTOFMEMORY;
982         return S_OK;
983     }
984     switch (V_VT( var ))
985     {
986     case VT_BOOL:
987         *val = V_BOOL( var );
988         *type = CIM_BOOLEAN;
989         break;
990     case VT_BSTR:
991         *val = (INT_PTR)heap_strdupW( V_BSTR( var ) );
992         if (!*val) return E_OUTOFMEMORY;
993         *type = CIM_STRING;
994         break;
995     case VT_I2:
996         *val = V_I2( var );
997         *type = CIM_SINT16;
998         break;
999     case VT_UI2:
1000         *val = V_UI2( var );
1001         *type = CIM_UINT16;
1002         break;
1003     case VT_I4:
1004         *val = V_I4( var );
1005         *type = CIM_SINT32;
1006         break;
1007     case VT_UI4:
1008         *val = V_UI4( var );
1009         *type = CIM_UINT32;
1010         break;
1011     case VT_NULL:
1012         *val = 0;
1013         break;
1014     default:
1015         ERR("unhandled type %u\n", V_VT( var ));
1016         return WBEM_E_FAILED;
1017     }
1018     return S_OK;
1019 }
1020 
1021 HRESULT put_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *var, CIMTYPE type )
1022 {
1023     HRESULT hr;
1024     UINT column, row = view->result[index];
1025     LONGLONG val;
1026 
1027     hr = get_column_index( view->table, name, &column );
1028     if (hr != S_OK)
1029     {
1030         FIXME("no support for creating new properties\n");
1031         return WBEM_E_FAILED;
1032     }
1033     if (is_method( view->table, column ) || !(view->table->columns[column].type & COL_FLAG_DYNAMIC))
1034         return WBEM_E_FAILED;
1035 
1036     hr = to_longlong( var, &val, &type );
1037     if (hr != S_OK) return hr;
1038 
1039     return set_value( view->table, row, column, val, type );
1040 }
1041 
1042 HRESULT get_properties( const struct view *view, LONG flags, SAFEARRAY **props )
1043 {
1044     SAFEARRAY *sa;
1045     BSTR str;
1046     UINT i, num_props = count_selected_properties( view );
1047     LONG j;
1048 
1049     if (!(sa = SafeArrayCreateVector( VT_BSTR, 0, num_props ))) return E_OUTOFMEMORY;
1050 
1051     for (i = 0, j = 0; i < view->table->num_cols; i++)
1052     {
1053         BOOL is_system;
1054 
1055         if (is_method( view->table, i )) continue;
1056         if (!is_selected_prop( view, view->table->columns[i].name )) continue;
1057 
1058         is_system = is_system_prop( view->table->columns[i].name );
1059         if ((flags & WBEM_FLAG_NONSYSTEM_ONLY) && is_system) continue;
1060         else if ((flags & WBEM_FLAG_SYSTEM_ONLY) && !is_system) continue;
1061 
1062         str = SysAllocString( view->table->columns[i].name );
1063         if (!str || SafeArrayPutElement( sa, &j, str ) != S_OK)
1064         {
1065             SysFreeString( str );
1066             SafeArrayDestroy( sa );
1067             return E_OUTOFMEMORY;
1068         }
1069         SysFreeString( str );
1070         j++;
1071     }
1072     *props = sa;
1073     return S_OK;
1074 }
1075