xref: /reactos/dll/win32/wbemprox/query.c (revision d2c71d76)
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 = ARRAY_SIZE( server );
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         if (ret)
672         {
673             V_VT( ret ) = VT_BSTR;
674             V_BSTR( ret ) = build_classname( view );
675         }
676         if (type) *type = CIM_STRING;
677         return S_OK;
678     }
679     if (!strcmpiW( name, genusW ))
680     {
681         if (ret)
682         {
683             V_VT( ret ) = VT_I4;
684             V_I4( ret ) = WBEM_GENUS_INSTANCE; /* FIXME */
685         }
686         if (type) *type = CIM_SINT32;
687         return S_OK;
688     }
689     else if (!strcmpiW( name, namespaceW ))
690     {
691         if (ret)
692         {
693             V_VT( ret ) = VT_BSTR;
694             V_BSTR( ret ) = build_namespace( view );
695         }
696         if (type) *type = CIM_STRING;
697         return S_OK;
698     }
699     else if (!strcmpiW( name, pathW ))
700     {
701         if (ret)
702         {
703             V_VT( ret ) = VT_BSTR;
704             V_BSTR( ret ) = build_path( view, index, name );
705         }
706         if (type) *type = CIM_STRING;
707         return S_OK;
708     }
709     if (!strcmpiW( name, propcountW ))
710     {
711         if (ret)
712         {
713             V_VT( ret ) = VT_I4;
714             V_I4( ret ) = count_selected_properties( view );
715         }
716         if (type) *type = CIM_SINT32;
717         return S_OK;
718     }
719     else if (!strcmpiW( name, relpathW ))
720     {
721         if (ret)
722         {
723             V_VT( ret ) = VT_BSTR;
724             V_BSTR( ret ) = build_relpath( view, index, name );
725         }
726         if (type) *type = CIM_STRING;
727         return S_OK;
728     }
729     else if (!strcmpiW( name, serverW ))
730     {
731         if (ret)
732         {
733             V_VT( ret ) = VT_BSTR;
734             V_BSTR( ret ) = build_servername( view );
735         }
736         if (type) *type = CIM_STRING;
737         return S_OK;
738     }
739     FIXME("system property %s not implemented\n", debugstr_w(name));
740     return WBEM_E_NOT_FOUND;
741 }
742 
743 VARTYPE to_vartype( CIMTYPE type )
744 {
745     switch (type)
746     {
747     case CIM_BOOLEAN:  return VT_BOOL;
748     case CIM_STRING:
749     case CIM_DATETIME: return VT_BSTR;
750     case CIM_SINT8:    return VT_I1;
751     case CIM_UINT8:    return VT_UI1;
752     case CIM_SINT16:   return VT_I2;
753     case CIM_UINT16:   return VT_UI2;
754     case CIM_SINT32:   return VT_I4;
755     case CIM_UINT32:   return VT_UI4;
756     case CIM_SINT64:   return VT_I8;
757     case CIM_UINT64:   return VT_UI8;
758     default:
759         ERR("unhandled type %u\n", type);
760         break;
761     }
762     return 0;
763 }
764 
765 SAFEARRAY *to_safearray( const struct array *array, CIMTYPE type )
766 {
767     SAFEARRAY *ret;
768     UINT size = get_type_size( type );
769     VARTYPE vartype = to_vartype( type );
770     LONG i;
771 
772     if (!array || !(ret = SafeArrayCreateVector( vartype, 0, array->count ))) return NULL;
773 
774     for (i = 0; i < array->count; i++)
775     {
776         void *ptr = (char *)array->ptr + i * size;
777         if (vartype == VT_BSTR)
778         {
779             BSTR str = SysAllocString( *(const WCHAR **)ptr );
780             if (!str || SafeArrayPutElement( ret, &i, str ) != S_OK)
781             {
782                 SysFreeString( str );
783                 SafeArrayDestroy( ret );
784                 return NULL;
785             }
786             SysFreeString( str );
787         }
788         else if (SafeArrayPutElement( ret, &i, ptr ) != S_OK)
789         {
790             SafeArrayDestroy( ret );
791             return NULL;
792         }
793     }
794     return ret;
795 }
796 
797 void set_variant( VARTYPE type, LONGLONG val, void *val_ptr, VARIANT *ret )
798 {
799     if (type & VT_ARRAY)
800     {
801         V_VT( ret ) = type;
802         V_ARRAY( ret ) = val_ptr;
803         return;
804     }
805     switch (type)
806     {
807     case VT_BOOL:
808         V_BOOL( ret ) = val;
809         break;
810     case VT_BSTR:
811         V_BSTR( ret ) = val_ptr;
812         break;
813     case VT_I1:
814         V_I1( ret ) = val;
815         break;
816     case VT_UI1:
817         V_UI1( ret ) = val;
818         break;
819     case VT_I2:
820         V_I2( ret ) = val;
821         break;
822     case VT_UI2:
823         V_UI2( ret ) = val;
824         break;
825     case VT_I4:
826         V_I4( ret ) = val;
827         break;
828     case VT_UI4:
829         V_UI4( ret ) = val;
830         break;
831     case VT_NULL:
832         break;
833     default:
834         ERR("unhandled variant type %u\n", type);
835         return;
836     }
837     V_VT( ret ) = type;
838 }
839 
840 HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *ret,
841                      CIMTYPE *type, LONG *flavor )
842 {
843     HRESULT hr;
844     UINT column, row;
845     VARTYPE vartype;
846     void *val_ptr = NULL;
847     LONGLONG val;
848 
849     if (is_system_prop( name )) return get_system_propval( view, index, name, ret, type, flavor );
850     if (!view->count || !is_selected_prop( view, name )) return WBEM_E_NOT_FOUND;
851 
852     hr = get_column_index( view->table, name, &column );
853     if (hr != S_OK || is_method( view->table, column )) return WBEM_E_NOT_FOUND;
854 
855     row = view->result[index];
856     hr = get_value( view->table, row, column, &val );
857     if (hr != S_OK) return hr;
858 
859     if (type) *type = view->table->columns[column].type & COL_TYPE_MASK;
860     if (flavor) *flavor = 0;
861 
862     if (!ret) return S_OK;
863 
864     vartype = view->table->columns[column].vartype;
865     if (view->table->columns[column].type & CIM_FLAG_ARRAY)
866     {
867         CIMTYPE basetype = view->table->columns[column].type & CIM_TYPE_MASK;
868 
869         val_ptr = to_safearray( (const struct array *)(INT_PTR)val, basetype );
870         if (!val_ptr) vartype = VT_NULL;
871         else if (!vartype) vartype = to_vartype( basetype ) | VT_ARRAY;
872         set_variant( vartype, val, val_ptr, ret );
873         return S_OK;
874     }
875 
876     switch (view->table->columns[column].type & COL_TYPE_MASK)
877     {
878     case CIM_BOOLEAN:
879         if (!vartype) vartype = VT_BOOL;
880         break;
881     case CIM_STRING:
882     case CIM_DATETIME:
883         if (val)
884         {
885             vartype = VT_BSTR;
886             val_ptr = SysAllocString( (const WCHAR *)(INT_PTR)val );
887         }
888         else
889             vartype = VT_NULL;
890         break;
891     case CIM_SINT8:
892         if (!vartype) vartype = VT_I1;
893         break;
894     case CIM_UINT8:
895         if (!vartype) vartype = VT_UI1;
896         break;
897     case CIM_SINT16:
898         if (!vartype) vartype = VT_I2;
899         break;
900     case CIM_UINT16:
901         if (!vartype) vartype = VT_UI2;
902         break;
903     case CIM_SINT32:
904         if (!vartype) vartype = VT_I4;
905         break;
906     case CIM_UINT32:
907         if (!vartype) vartype = VT_UI4;
908         break;
909     case CIM_SINT64:
910         vartype = VT_BSTR;
911         val_ptr = get_value_bstr( view->table, row, column );
912         break;
913     case CIM_UINT64:
914         vartype = VT_BSTR;
915         val_ptr = get_value_bstr( view->table, row, column );
916         break;
917     default:
918         ERR("unhandled column type %u\n", view->table->columns[column].type);
919         return WBEM_E_FAILED;
920     }
921 
922     set_variant( vartype, val, val_ptr, ret );
923     return S_OK;
924 }
925 
926 static CIMTYPE to_cimtype( VARTYPE type )
927 {
928     switch (type)
929     {
930     case VT_BOOL:  return CIM_BOOLEAN;
931     case VT_BSTR:  return CIM_STRING;
932     case VT_I1:    return CIM_SINT8;
933     case VT_UI1:   return CIM_UINT8;
934     case VT_I2:    return CIM_SINT16;
935     case VT_UI2:   return CIM_UINT16;
936     case VT_I4:    return CIM_SINT32;
937     case VT_UI4:   return CIM_UINT32;
938     case VT_I8:    return CIM_SINT64;
939     case VT_UI8:   return CIM_UINT64;
940     default:
941         ERR("unhandled type %u\n", type);
942         break;
943     }
944     return 0;
945 }
946 
947 static struct array *to_array( VARIANT *var, CIMTYPE *type )
948 {
949     struct array *ret;
950     LONG bound, i;
951     VARTYPE vartype;
952     CIMTYPE basetype;
953     UINT size;
954 
955     if (SafeArrayGetVartype( V_ARRAY( var ), &vartype ) != S_OK) return NULL;
956     if (!(basetype = to_cimtype( vartype ))) return NULL;
957     if (SafeArrayGetUBound( V_ARRAY( var ), 1, &bound ) != S_OK) return NULL;
958     if (!(ret = heap_alloc( sizeof(struct array) ))) return NULL;
959 
960     ret->count = bound + 1;
961     size = get_type_size( basetype );
962     if (!(ret->ptr = heap_alloc_zero( ret->count * size )))
963     {
964         heap_free( ret );
965         return NULL;
966     }
967     for (i = 0; i < ret->count; i++)
968     {
969         void *ptr = (char *)ret->ptr + i * size;
970         if (vartype == VT_BSTR)
971         {
972             BSTR str;
973             if (SafeArrayGetElement( V_ARRAY( var ), &i, &str ) != S_OK)
974             {
975                 destroy_array( ret, basetype );
976                 return NULL;
977             }
978             *(WCHAR **)ptr = heap_strdupW( str );
979             SysFreeString( str );
980             if (!*(WCHAR **)ptr)
981             {
982                 destroy_array( ret, basetype );
983                 return NULL;
984             }
985         }
986         else if (SafeArrayGetElement( V_ARRAY( var ), &i, ptr ) != S_OK)
987         {
988             destroy_array( ret, basetype );
989             return NULL;
990         }
991     }
992     *type = basetype | CIM_FLAG_ARRAY;
993     return ret;
994 }
995 
996 HRESULT to_longlong( VARIANT *var, LONGLONG *val, CIMTYPE *type )
997 {
998     if (!var)
999     {
1000         *val = 0;
1001         return S_OK;
1002     }
1003     if (V_VT( var ) & VT_ARRAY)
1004     {
1005         *val = (INT_PTR)to_array( var, type );
1006         if (!*val) return E_OUTOFMEMORY;
1007         return S_OK;
1008     }
1009     switch (V_VT( var ))
1010     {
1011     case VT_BOOL:
1012         *val = V_BOOL( var );
1013         *type = CIM_BOOLEAN;
1014         break;
1015     case VT_BSTR:
1016         *val = (INT_PTR)heap_strdupW( V_BSTR( var ) );
1017         if (!*val) return E_OUTOFMEMORY;
1018         *type = CIM_STRING;
1019         break;
1020     case VT_I2:
1021         *val = V_I2( var );
1022         *type = CIM_SINT16;
1023         break;
1024     case VT_UI2:
1025         *val = V_UI2( var );
1026         *type = CIM_UINT16;
1027         break;
1028     case VT_I4:
1029         *val = V_I4( var );
1030         *type = CIM_SINT32;
1031         break;
1032     case VT_UI4:
1033         *val = V_UI4( var );
1034         *type = CIM_UINT32;
1035         break;
1036     case VT_NULL:
1037         *val = 0;
1038         break;
1039     default:
1040         ERR("unhandled type %u\n", V_VT( var ));
1041         return WBEM_E_FAILED;
1042     }
1043     return S_OK;
1044 }
1045 
1046 HRESULT put_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *var, CIMTYPE type )
1047 {
1048     HRESULT hr;
1049     UINT column, row = view->result[index];
1050     LONGLONG val;
1051 
1052     hr = get_column_index( view->table, name, &column );
1053     if (hr != S_OK)
1054     {
1055         FIXME("no support for creating new properties\n");
1056         return WBEM_E_FAILED;
1057     }
1058     if (is_method( view->table, column ) || !(view->table->columns[column].type & COL_FLAG_DYNAMIC))
1059         return WBEM_E_FAILED;
1060 
1061     hr = to_longlong( var, &val, &type );
1062     if (hr != S_OK) return hr;
1063 
1064     return set_value( view->table, row, column, val, type );
1065 }
1066 
1067 HRESULT get_properties( const struct view *view, LONG flags, SAFEARRAY **props )
1068 {
1069     SAFEARRAY *sa;
1070     BSTR str;
1071     UINT i, num_props = count_selected_properties( view );
1072     LONG j;
1073 
1074     if (!(sa = SafeArrayCreateVector( VT_BSTR, 0, num_props ))) return E_OUTOFMEMORY;
1075 
1076     for (i = 0, j = 0; i < view->table->num_cols; i++)
1077     {
1078         BOOL is_system;
1079 
1080         if (is_method( view->table, i )) continue;
1081         if (!is_selected_prop( view, view->table->columns[i].name )) continue;
1082 
1083         is_system = is_system_prop( view->table->columns[i].name );
1084         if ((flags & WBEM_FLAG_NONSYSTEM_ONLY) && is_system) continue;
1085         else if ((flags & WBEM_FLAG_SYSTEM_ONLY) && !is_system) continue;
1086 
1087         str = SysAllocString( view->table->columns[i].name );
1088         if (!str || SafeArrayPutElement( sa, &j, str ) != S_OK)
1089         {
1090             SysFreeString( str );
1091             SafeArrayDestroy( sa );
1092             return E_OUTOFMEMORY;
1093         }
1094         SysFreeString( str );
1095         j++;
1096     }
1097     *props = sa;
1098     return S_OK;
1099 }
1100