Release 1.5.29.
[wine] / dlls / wbemprox / query.c
1 /*
2  * Copyright 2012 Hans Leidekker for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #define COBJMACROS
20
21 #include "config.h"
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wbemcli.h"
27
28 #include "wine/debug.h"
29 #include "wbemprox_private.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(wbemprox);
32
33 HRESULT create_view( const struct property *proplist, const WCHAR *class,
34                      const struct expr *cond, struct view **ret )
35 {
36     struct view *view = heap_alloc( sizeof(struct view) );
37
38     if (!view) return E_OUTOFMEMORY;
39     view->proplist = proplist;
40     view->table    = 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 && toupperW( p[1] ) != toupperW( q[1] )) p++;
67             if (!*p) return TRUE;
68         }
69         if (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 inline BOOL is_strcmp( const struct complex_expr *expr )
112 {
113     return ((expr->left->type == EXPR_PROPVAL && expr->right->type == EXPR_SVAL) ||
114             (expr->left->type == EXPR_SVAL && expr->right->type == EXPR_PROPVAL));
115 }
116
117 static HRESULT eval_cond( const struct table *, UINT, const struct expr *, LONGLONG * );
118
119 static HRESULT eval_binary( const struct table *table, UINT row, const struct complex_expr *expr,
120                             LONGLONG *val )
121 {
122     HRESULT lret, rret;
123     LONGLONG lval, rval;
124
125     lret = eval_cond( table, row, expr->left, &lval );
126     rret = eval_cond( table, row, expr->right, &rval );
127     if (lret != S_OK || rret != S_OK) return WBEM_E_INVALID_QUERY;
128
129     if (is_strcmp( expr ))
130     {
131         const WCHAR *lstr = (const WCHAR *)(INT_PTR)lval;
132         const WCHAR *rstr = (const WCHAR *)(INT_PTR)rval;
133
134         return eval_strcmp( expr->op, lstr, rstr, val );
135     }
136     switch (expr->op)
137     {
138     case OP_EQ:
139         *val = (lval == rval);
140         break;
141     case OP_AND:
142         *val = (lval && rval);
143         break;
144     case OP_OR:
145         *val = (lval || rval);
146         break;
147     case OP_GT:
148         *val = (lval > rval);
149         break;
150     case OP_LT:
151         *val = (lval < rval);
152         break;
153     case OP_LE:
154         *val = (lval <= rval);
155         break;
156     case OP_GE:
157         *val = (lval >= rval);
158         break;
159     case OP_NE:
160         *val = (lval != rval);
161         break;
162     default:
163         ERR("unhandled operator %u\n", expr->op);
164         return WBEM_E_INVALID_QUERY;
165     }
166     return S_OK;
167 }
168
169 static HRESULT eval_unary( const struct table *table, UINT row, const struct complex_expr *expr,
170                            LONGLONG *val )
171
172 {
173     HRESULT hr;
174     UINT column;
175     LONGLONG lval;
176
177     hr = get_column_index( table, expr->left->u.propval->name, &column );
178     if (hr != S_OK)
179         return hr;
180
181     hr = get_value( table, row, column, &lval );
182     if (hr != S_OK)
183         return hr;
184
185     switch (expr->op)
186     {
187     case OP_ISNULL:
188         *val = !lval;
189         break;
190     case OP_NOTNULL:
191         *val = lval;
192         break;
193     default:
194         ERR("unknown operator %u\n", expr->op);
195         return WBEM_E_INVALID_QUERY;
196     }
197     return S_OK;
198 }
199
200 static HRESULT eval_propval( const struct table *table, UINT row, const struct property *propval,
201                              LONGLONG *val )
202
203 {
204     HRESULT hr;
205     UINT column;
206
207     hr = get_column_index( table, propval->name, &column );
208     if (hr != S_OK)
209         return hr;
210
211     return get_value( table, row, column, val );
212 }
213
214 static HRESULT eval_cond( const struct table *table, UINT row, const struct expr *cond,
215                           LONGLONG *val )
216 {
217     if (!cond)
218     {
219         *val = 1;
220         return S_OK;
221     }
222     switch (cond->type)
223     {
224     case EXPR_COMPLEX:
225         return eval_binary( table, row, &cond->u.expr, val );
226     case EXPR_UNARY:
227         return eval_unary( table, row, &cond->u.expr, val );
228     case EXPR_PROPVAL:
229         return eval_propval( table, row, cond->u.propval, val );
230     case EXPR_SVAL:
231         *val = (INT_PTR)cond->u.sval;
232         return S_OK;
233     case EXPR_IVAL:
234     case EXPR_BVAL:
235         *val = cond->u.ival;
236         return S_OK;
237     default:
238         ERR("invalid expression type\n");
239         break;
240     }
241     return WBEM_E_INVALID_QUERY;
242 }
243
244 static HRESULT execute_view( struct view *view )
245 {
246     UINT i, j = 0, len;
247
248     if (!view->table || !view->table->num_rows) return S_OK;
249
250     len = min( view->table->num_rows, 16 );
251     if (!(view->result = heap_alloc( len * sizeof(UINT) ))) return E_OUTOFMEMORY;
252
253     for (i = 0; i < view->table->num_rows; i++)
254     {
255         HRESULT hr;
256         LONGLONG val = 0;
257
258         if (j >= len)
259         {
260             UINT *tmp;
261             len *= 2;
262             if (!(tmp = heap_realloc( view->result, len * sizeof(UINT) ))) return E_OUTOFMEMORY;
263             view->result = tmp;
264         }
265         if ((hr = eval_cond( view->table, i, view->cond, &val )) != S_OK) return hr;
266         if (val) view->result[j++] = i;
267     }
268     view->count = j;
269     return S_OK;
270 }
271
272 static struct query *create_query(void)
273 {
274     struct query *query;
275
276     if (!(query = heap_alloc( sizeof(*query) ))) return NULL;
277     list_init( &query->mem );
278     query->refs = 1;
279     return query;
280 }
281
282 static void free_query( struct query *query )
283 {
284     struct list *mem, *next;
285
286     destroy_view( query->view );
287     LIST_FOR_EACH_SAFE( mem, next, &query->mem )
288     {
289         heap_free( mem );
290     }
291     heap_free( query );
292 }
293
294 struct query *addref_query( struct query *query )
295 {
296     InterlockedIncrement( &query->refs );
297     return query;
298 }
299
300 void release_query( struct query *query )
301 {
302     if (!InterlockedDecrement( &query->refs )) free_query( query );
303 }
304
305 HRESULT exec_query( const WCHAR *str, IEnumWbemClassObject **result )
306 {
307     HRESULT hr;
308     struct query *query;
309
310     *result = NULL;
311     if (!(query = create_query())) return E_OUTOFMEMORY;
312     hr = parse_query( str, &query->view, &query->mem );
313     if (hr != S_OK) goto done;
314     hr = execute_view( query->view );
315     if (hr != S_OK) goto done;
316     hr = EnumWbemClassObject_create( NULL, query, (void **)result );
317
318 done:
319     release_query( query );
320     return hr;
321 }
322
323 static BOOL is_selected_prop( const struct view *view, const WCHAR *name )
324 {
325     const struct property *prop = view->proplist;
326
327     if (!prop) return TRUE;
328     while (prop)
329     {
330         if (!strcmpiW( prop->name, name )) return TRUE;
331         prop = prop->next;
332     }
333     return FALSE;
334 }
335
336 static BOOL is_system_prop( const WCHAR *name )
337 {
338     return (name[0] == '_' && name[1] == '_');
339 }
340
341 static BSTR build_servername( const struct view *view )
342 {
343     WCHAR server[MAX_COMPUTERNAME_LENGTH + 1], *p;
344     DWORD len = sizeof(server)/sizeof(server[0]);
345
346     if (view->proplist) return NULL;
347
348     if (!(GetComputerNameW( server, &len ))) return NULL;
349     for (p = server; *p; p++) *p = toupperW( *p );
350     return SysAllocString( server );
351 }
352
353 static BSTR build_classname( const struct view *view )
354 {
355     return SysAllocString( view->table->name );
356 }
357
358 static BSTR build_namespace( const struct view *view )
359 {
360     static const WCHAR cimv2W[] = {'R','O','O','T','\\','C','I','M','V','2',0};
361
362     if (view->proplist) return NULL;
363     return SysAllocString( cimv2W );
364 }
365
366 static BSTR build_proplist( const struct view *view, UINT index, UINT count, UINT *len )
367 {
368     static const WCHAR fmtW[] = {'%','s','=','%','s',0};
369     UINT i, j, offset, row = view->result[index];
370     BSTR *values, ret = NULL;
371
372     if (!(values = heap_alloc( count * sizeof(BSTR) ))) return NULL;
373
374     *len = j = 0;
375     for (i = 0; i < view->table->num_cols; i++)
376     {
377         if (view->table->columns[i].type & COL_FLAG_KEY)
378         {
379             const WCHAR *name = view->table->columns[i].name;
380
381             values[j] = get_value_bstr( view->table, row, i );
382             *len += strlenW( fmtW ) + strlenW( name ) + strlenW( values[j] );
383             j++;
384         }
385     }
386     if ((ret = SysAllocStringLen( NULL, *len )))
387     {
388         offset = j = 0;
389         for (i = 0; i < view->table->num_cols; i++)
390         {
391             if (view->table->columns[i].type & COL_FLAG_KEY)
392             {
393                 const WCHAR *name = view->table->columns[i].name;
394
395                 offset += sprintfW( ret + offset, fmtW, name, values[j] );
396                 if (j < count - 1) ret[offset++] = ',';
397                 j++;
398             }
399         }
400     }
401     for (i = 0; i < count; i++) SysFreeString( values[i] );
402     heap_free( values );
403     return ret;
404 }
405
406 static UINT count_key_columns( const struct view *view )
407 {
408     UINT i, num_keys = 0;
409
410     for (i = 0; i < view->table->num_cols; i++)
411     {
412         if (view->table->columns[i].type & COL_FLAG_KEY) num_keys++;
413     }
414     return num_keys;
415 }
416
417 static BSTR build_relpath( const struct view *view, UINT index, const WCHAR *name )
418 {
419     static const WCHAR fmtW[] = {'%','s','.','%','s',0};
420     BSTR class, proplist, ret = NULL;
421     UINT num_keys, len;
422
423     if (view->proplist) return NULL;
424
425     if (!(class = build_classname( view ))) return NULL;
426     if (!(num_keys = count_key_columns( view ))) return class;
427     if (!(proplist = build_proplist( view, index, num_keys, &len ))) goto done;
428
429     len += strlenW( fmtW ) + SysStringLen( class );
430     if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
431     sprintfW( ret, fmtW, class, proplist );
432
433 done:
434     SysFreeString( class );
435     SysFreeString( proplist );
436     return ret;
437 }
438
439 static BSTR build_path( const struct view *view, UINT index, const WCHAR *name )
440 {
441     static const WCHAR fmtW[] = {'\\','\\','%','s','\\','%','s',':','%','s',0};
442     BSTR server, namespace = NULL, relpath = NULL, ret = NULL;
443     UINT len;
444
445     if (view->proplist) return NULL;
446
447     if (!(server = build_servername( view ))) return NULL;
448     if (!(namespace = build_namespace( view ))) goto done;
449     if (!(relpath = build_relpath( view, index, name ))) goto done;
450
451     len = strlenW( fmtW ) + SysStringLen( server ) + SysStringLen( namespace ) + SysStringLen( relpath );
452     if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
453     sprintfW( ret, fmtW, server, namespace, relpath );
454
455 done:
456     SysFreeString( server );
457     SysFreeString( namespace );
458     SysFreeString( relpath );
459     return ret;
460 }
461
462 static inline BOOL is_method( const struct table *table, UINT column )
463 {
464     return table->columns[column].type & COL_FLAG_METHOD;
465 }
466
467 static UINT count_properties( const struct view *view )
468 {
469     UINT i, num_props = 0;
470
471     for (i = 0; i < view->table->num_cols; i++)
472     {
473         if (!is_method( view->table, i)) num_props++;
474     }
475     return num_props;
476 }
477
478 static UINT count_selected_properties( const struct view *view )
479 {
480     const struct property *prop = view->proplist;
481     UINT count;
482
483     if (!prop) return count_properties( view );
484
485     count = 1;
486     while ((prop = prop->next)) count++;
487     return count;
488 }
489
490 static HRESULT get_system_propval( const struct view *view, UINT index, const WCHAR *name,
491                                    VARIANT *ret, CIMTYPE *type, LONG *flavor )
492 {
493     static const WCHAR classW[] = {'_','_','C','L','A','S','S',0};
494     static const WCHAR genusW[] = {'_','_','G','E','N','U','S',0};
495     static const WCHAR pathW[] = {'_','_','P','A','T','H',0};
496     static const WCHAR namespaceW[] = {'_','_','N','A','M','E','S','P','A','C','E',0};
497     static const WCHAR propcountW[] = {'_','_','P','R','O','P','E','R','T','Y','_','C','O','U','N','T',0};
498     static const WCHAR relpathW[] = {'_','_','R','E','L','P','A','T','H',0};
499     static const WCHAR serverW[] = {'_','_','S','E','R','V','E','R',0};
500
501     if (flavor) *flavor = WBEM_FLAVOR_ORIGIN_SYSTEM;
502
503     if (!strcmpiW( name, classW ))
504     {
505         V_VT( ret ) = VT_BSTR;
506         V_BSTR( ret ) = build_classname( view );
507         if (type) *type = CIM_STRING;
508         return S_OK;
509     }
510     if (!strcmpiW( name, genusW ))
511     {
512         V_VT( ret ) = VT_I4;
513         V_I4( ret ) = WBEM_GENUS_INSTANCE; /* FIXME */
514         if (type) *type = CIM_SINT32;
515         return S_OK;
516     }
517     else if (!strcmpiW( name, namespaceW ))
518     {
519         V_VT( ret ) = VT_BSTR;
520         V_BSTR( ret ) = build_namespace( view );
521         if (type) *type = CIM_STRING;
522         return S_OK;
523     }
524     else if (!strcmpiW( name, pathW ))
525     {
526         V_VT( ret ) = VT_BSTR;
527         V_BSTR( ret ) = build_path( view, index, name );
528         if (type) *type = CIM_STRING;
529         return S_OK;
530     }
531     if (!strcmpiW( name, propcountW ))
532     {
533         V_VT( ret ) = VT_I4;
534         V_I4( ret ) = count_selected_properties( view );
535         if (type) *type = CIM_SINT32;
536         return S_OK;
537     }
538     else if (!strcmpiW( name, relpathW ))
539     {
540         V_VT( ret ) = VT_BSTR;
541         V_BSTR( ret ) = build_relpath( view, index, name );
542         if (type) *type = CIM_STRING;
543         return S_OK;
544     }
545     else if (!strcmpiW( name, serverW ))
546     {
547         V_VT( ret ) = VT_BSTR;
548         V_BSTR( ret ) = build_servername( view );
549         if (type) *type = CIM_STRING;
550         return S_OK;
551     }
552     FIXME("system property %s not implemented\n", debugstr_w(name));
553     return WBEM_E_NOT_FOUND;
554 }
555
556 VARTYPE to_vartype( CIMTYPE type )
557 {
558     switch (type)
559     {
560     case CIM_BOOLEAN:  return VT_BOOL;
561     case CIM_STRING:
562     case CIM_DATETIME: return VT_BSTR;
563     case CIM_SINT16:   return VT_I2;
564     case CIM_UINT16:   return VT_UI2;
565     case CIM_SINT32:   return VT_I4;
566     case CIM_UINT32:   return VT_UI4;
567     case CIM_SINT64:   return VT_I8;
568     case CIM_UINT64:   return VT_UI8;
569     default:
570         ERR("unhandled type %u\n", type);
571         break;
572     }
573     return 0;
574 }
575
576 SAFEARRAY *to_safearray( const struct array *array, CIMTYPE type )
577 {
578     SAFEARRAY *ret;
579     UINT size = get_type_size( type );
580     VARTYPE vartype = to_vartype( type );
581     LONG i;
582
583     if (!(ret = SafeArrayCreateVector( vartype, 0, array->count ))) return NULL;
584
585     for (i = 0; i < array->count; i++)
586     {
587         void *ptr = (char *)array->ptr + i * size;
588         if (vartype == VT_BSTR)
589         {
590             BSTR str = SysAllocString( *(const WCHAR **)ptr );
591             if (!str || SafeArrayPutElement( ret, &i, str ) != S_OK)
592             {
593                 SysFreeString( str );
594                 SafeArrayDestroy( ret );
595                 return NULL;
596             }
597         }
598         else if (SafeArrayPutElement( ret, &i, ptr ) != S_OK)
599         {
600             SafeArrayDestroy( ret );
601             return NULL;
602         }
603     }
604     return ret;
605 }
606
607 void set_variant( VARTYPE type, LONGLONG val, void *val_ptr, VARIANT *ret )
608 {
609     if (type & VT_ARRAY)
610     {
611         V_VT( ret ) = type;
612         V_ARRAY( ret ) = val_ptr;
613         return;
614     }
615     switch (type)
616     {
617     case VT_BOOL:
618         V_BOOL( ret ) = val;
619         break;
620     case VT_BSTR:
621         V_BSTR( ret ) = val_ptr;
622         break;
623     case VT_I2:
624         V_I2( ret ) = val;
625         break;
626     case VT_UI2:
627         V_UI2( ret ) = val;
628         break;
629     case VT_I4:
630         V_I4( ret ) = val;
631         break;
632     case VT_UI4:
633         V_UI4( ret ) = val;
634         break;
635     case VT_NULL:
636         break;
637     default:
638         ERR("unhandled variant type %u\n", type);
639         return;
640     }
641     V_VT( ret ) = type;
642 }
643
644 HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *ret,
645                      CIMTYPE *type, LONG *flavor )
646 {
647     HRESULT hr;
648     UINT column, row;
649     VARTYPE vartype;
650     void *val_ptr = NULL;
651     LONGLONG val;
652
653     if (is_system_prop( name )) return get_system_propval( view, index, name, ret, type, flavor );
654     if (!view->count || !is_selected_prop( view, name )) return WBEM_E_NOT_FOUND;
655
656     hr = get_column_index( view->table, name, &column );
657     if (hr != S_OK || is_method( view->table, column )) return WBEM_E_NOT_FOUND;
658
659     row = view->result[index];
660     hr = get_value( view->table, row, column, &val );
661     if (hr != S_OK) return hr;
662
663     vartype = view->table->columns[column].vartype;
664     if (view->table->columns[column].type & CIM_FLAG_ARRAY)
665     {
666         CIMTYPE basetype = view->table->columns[column].type & CIM_TYPE_MASK;
667
668         val_ptr = to_safearray( (const struct array *)(INT_PTR)val, basetype );
669         if (!vartype) vartype = to_vartype( basetype ) | VT_ARRAY;
670         goto done;
671     }
672     switch (view->table->columns[column].type & COL_TYPE_MASK)
673     {
674     case CIM_BOOLEAN:
675         if (!vartype) vartype = VT_BOOL;
676         break;
677     case CIM_STRING:
678     case CIM_DATETIME:
679         if (val)
680         {
681             vartype = VT_BSTR;
682             val_ptr = SysAllocString( (const WCHAR *)(INT_PTR)val );
683         }
684         else
685             vartype = VT_NULL;
686         break;
687     case CIM_SINT16:
688         if (!vartype) vartype = VT_I2;
689         break;
690     case CIM_UINT16:
691         if (!vartype) vartype = VT_UI2;
692         break;
693     case CIM_SINT32:
694         if (!vartype) vartype = VT_I4;
695         break;
696     case CIM_UINT32:
697         if (!vartype) vartype = VT_UI4;
698         break;
699     case CIM_SINT64:
700         vartype = VT_BSTR;
701         val_ptr = get_value_bstr( view->table, row, column );
702         break;
703     case CIM_UINT64:
704         vartype = VT_BSTR;
705         val_ptr = get_value_bstr( view->table, row, column );
706         break;
707     default:
708         ERR("unhandled column type %u\n", view->table->columns[column].type);
709         return WBEM_E_FAILED;
710     }
711
712 done:
713     set_variant( vartype, val, val_ptr, ret );
714     if (type) *type = view->table->columns[column].type & COL_TYPE_MASK;
715     if (flavor) *flavor = 0;
716     return S_OK;
717 }
718
719 static CIMTYPE to_cimtype( VARTYPE type )
720 {
721     switch (type)
722     {
723     case VT_BOOL:  return CIM_BOOLEAN;
724     case VT_BSTR:  return CIM_STRING;
725     case VT_I2:    return CIM_SINT16;
726     case VT_UI2:   return CIM_UINT16;
727     case VT_I4:    return CIM_SINT32;
728     case VT_UI4:   return CIM_UINT32;
729     case VT_I8:    return CIM_SINT64;
730     case VT_UI8:   return CIM_UINT64;
731     default:
732         ERR("unhandled type %u\n", type);
733         break;
734     }
735     return 0;
736 }
737
738 static struct array *to_array( VARIANT *var, CIMTYPE *type )
739 {
740     struct array *ret;
741     LONG bound, i;
742     VARTYPE vartype;
743     CIMTYPE basetype;
744     UINT size;
745
746     if (SafeArrayGetVartype( V_ARRAY( var ), &vartype ) != S_OK) return NULL;
747     if (!(basetype = to_cimtype( vartype ))) return NULL;
748     if (SafeArrayGetUBound( V_ARRAY( var ), 1, &bound ) != S_OK) return NULL;
749     if (!(ret = heap_alloc( sizeof(struct array) ))) return NULL;
750
751     ret->count = bound + 1;
752     size = get_type_size( basetype );
753     if (!(ret->ptr = heap_alloc_zero( ret->count * size )))
754     {
755         heap_free( ret );
756         return NULL;
757     }
758     for (i = 0; i < ret->count; i++)
759     {
760         void *ptr = (char *)ret->ptr + i * size;
761         if (vartype == VT_BSTR)
762         {
763             BSTR str;
764             if (SafeArrayGetElement( V_ARRAY( var ), &i, &str ) != S_OK)
765             {
766                 destroy_array( ret, basetype );
767                 return NULL;
768             }
769             *(WCHAR **)ptr = heap_strdupW( str );
770             SysFreeString( str );
771             if (!*(WCHAR **)ptr)
772             {
773                 destroy_array( ret, basetype );
774                 return NULL;
775             }
776         }
777         else if (SafeArrayGetElement( V_ARRAY( var ), &i, ptr ) != S_OK)
778         {
779             destroy_array( ret, basetype );
780             return NULL;
781         }
782     }
783     *type = basetype | CIM_FLAG_ARRAY;
784     return ret;
785 }
786
787 HRESULT to_longlong( VARIANT *var, LONGLONG *val, CIMTYPE *type )
788 {
789     if (!var)
790     {
791         *val = 0;
792         return S_OK;
793     }
794     if (V_VT( var ) & VT_ARRAY)
795     {
796         *val = (INT_PTR)to_array( var, type );
797         if (!*val) return E_OUTOFMEMORY;
798         return S_OK;
799     }
800     switch (V_VT( var ))
801     {
802     case VT_BOOL:
803         *val = V_BOOL( var );
804         *type = CIM_BOOLEAN;
805         break;
806     case VT_BSTR:
807         *val = (INT_PTR)heap_strdupW( V_BSTR( var ) );
808         if (!*val) return E_OUTOFMEMORY;
809         *type = CIM_STRING;
810         break;
811     case VT_I2:
812         *val = V_I2( var );
813         *type = CIM_SINT16;
814         break;
815     case VT_UI2:
816         *val = V_UI2( var );
817         *type = CIM_UINT16;
818         break;
819     case VT_I4:
820         *val = V_I4( var );
821         *type = CIM_SINT32;
822         break;
823     case VT_UI4:
824         *val = V_UI4( var );
825         *type = CIM_UINT32;
826         break;
827     case VT_NULL:
828         *val = 0;
829         break;
830     default:
831         ERR("unhandled type %u\n", V_VT( var ));
832         return WBEM_E_FAILED;
833     }
834     return S_OK;
835 }
836
837 HRESULT put_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *var, CIMTYPE type )
838 {
839     HRESULT hr;
840     UINT column, row = view->result[index];
841     LONGLONG val;
842
843     hr = get_column_index( view->table, name, &column );
844     if (hr != S_OK)
845     {
846         FIXME("no support for creating new properties\n");
847         return WBEM_E_FAILED;
848     }
849     if (is_method( view->table, column ) || !(view->table->columns[column].type & COL_FLAG_DYNAMIC))
850         return WBEM_E_FAILED;
851
852     hr = to_longlong( var, &val, &type );
853     if (hr != S_OK) return hr;
854
855     return set_value( view->table, row, column, val, type );
856 }
857
858 HRESULT get_properties( const struct view *view, SAFEARRAY **props )
859 {
860     SAFEARRAY *sa;
861     BSTR str;
862     LONG i;
863     UINT num_props = count_properties( view );
864
865     if (!(sa = SafeArrayCreateVector( VT_BSTR, 0, num_props ))) return E_OUTOFMEMORY;
866
867     for (i = 0; i < view->table->num_cols; i++)
868     {
869         if (is_method( view->table, i )) continue;
870
871         str = SysAllocString( view->table->columns[i].name );
872         if (!str || SafeArrayPutElement( sa, &i, str ) != S_OK)
873         {
874             SysFreeString( str );
875             SafeArrayDestroy( sa );
876             return E_OUTOFMEMORY;
877         }
878     }
879     *props = sa;
880     return S_OK;
881 }