jscript: Get rid of BSTR in date.c.
[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->table) release_table( view->table );
51     heap_free( view->result );
52     heap_free( view );
53 }
54
55 static BOOL eval_like( const WCHAR *lstr, const WCHAR *rstr )
56 {
57     const WCHAR *p = lstr, *q = rstr;
58
59     while (*p && *q)
60     {
61         if (*q == '%')
62         {
63             while (*q == '%') q++;
64             if (!*q) return TRUE;
65             while (*p && toupperW( p[1] ) != toupperW( q[1] )) p++;
66             if (!*p) return TRUE;
67         }
68         if (toupperW( *p++ ) != toupperW( *q++ )) return FALSE;
69     }
70     return TRUE;
71 }
72
73 static HRESULT eval_strcmp( UINT op, const WCHAR *lstr, const WCHAR *rstr, LONGLONG *val )
74 {
75     if (!lstr || !rstr)
76     {
77         *val = 0;
78         return S_OK;
79     }
80     switch (op)
81     {
82     case OP_EQ:
83         *val = !strcmpW( lstr, rstr );
84         break;
85     case OP_GT:
86         *val = strcmpW( lstr, rstr ) > 0;
87         break;
88     case OP_LT:
89         *val = strcmpW( lstr, rstr ) < 0;
90         break;
91     case OP_LE:
92         *val = strcmpW( lstr, rstr ) <= 0;
93         break;
94     case OP_GE:
95         *val = strcmpW( lstr, rstr ) >= 0;
96         break;
97     case OP_NE:
98         *val = strcmpW( lstr, rstr );
99         break;
100     case OP_LIKE:
101         *val = eval_like( lstr, rstr );
102         break;
103     default:
104         ERR("unhandled operator %u\n", op);
105         return WBEM_E_INVALID_QUERY;
106     }
107     return S_OK;
108 }
109
110 static inline BOOL is_strcmp( const struct complex_expr *expr )
111 {
112     return ((expr->left->type == EXPR_PROPVAL && expr->right->type == EXPR_SVAL) ||
113             (expr->left->type == EXPR_SVAL && expr->right->type == EXPR_PROPVAL));
114 }
115
116 static HRESULT eval_cond( const struct table *, UINT, const struct expr *, LONGLONG * );
117
118 static HRESULT eval_binary( const struct table *table, UINT row, const struct complex_expr *expr,
119                             LONGLONG *val )
120 {
121     HRESULT lret, rret;
122     LONGLONG lval, rval;
123
124     lret = eval_cond( table, row, expr->left, &lval );
125     rret = eval_cond( table, row, expr->right, &rval );
126     if (lret != S_OK || rret != S_OK) return WBEM_E_INVALID_QUERY;
127
128     if (is_strcmp( expr ))
129     {
130         const WCHAR *lstr = (const WCHAR *)(INT_PTR)lval;
131         const WCHAR *rstr = (const WCHAR *)(INT_PTR)rval;
132
133         return eval_strcmp( expr->op, lstr, rstr, val );
134     }
135     switch (expr->op)
136     {
137     case OP_EQ:
138         *val = (lval == rval);
139         break;
140     case OP_AND:
141         *val = (lval && rval);
142         break;
143     case OP_OR:
144         *val = (lval || rval);
145         break;
146     case OP_GT:
147         *val = (lval > rval);
148         break;
149     case OP_LT:
150         *val = (lval < rval);
151         break;
152     case OP_LE:
153         *val = (lval <= rval);
154         break;
155     case OP_GE:
156         *val = (lval >= rval);
157         break;
158     case OP_NE:
159         *val = (lval != rval);
160         break;
161     default:
162         ERR("unhandled operator %u\n", expr->op);
163         return WBEM_E_INVALID_QUERY;
164     }
165     return S_OK;
166 }
167
168 static HRESULT eval_unary( const struct table *table, UINT row, const struct complex_expr *expr,
169                            LONGLONG *val )
170
171 {
172     HRESULT hr;
173     UINT column;
174     LONGLONG lval;
175
176     hr = get_column_index( table, expr->left->u.propval->name, &column );
177     if (hr != S_OK)
178         return hr;
179
180     hr = get_value( table, row, column, &lval );
181     if (hr != S_OK)
182         return hr;
183
184     switch (expr->op)
185     {
186     case OP_ISNULL:
187         *val = !lval;
188         break;
189     case OP_NOTNULL:
190         *val = lval;
191         break;
192     default:
193         ERR("unknown operator %u\n", expr->op);
194         return WBEM_E_INVALID_QUERY;
195     }
196     return S_OK;
197 }
198
199 static HRESULT eval_propval( const struct table *table, UINT row, const struct property *propval,
200                              LONGLONG *val )
201
202 {
203     HRESULT hr;
204     UINT column;
205
206     hr = get_column_index( table, propval->name, &column );
207     if (hr != S_OK)
208         return hr;
209
210     return get_value( table, row, column, val );
211 }
212
213 static HRESULT eval_cond( const struct table *table, UINT row, const struct expr *cond,
214                           LONGLONG *val )
215 {
216     if (!cond)
217     {
218         *val = 1;
219         return S_OK;
220     }
221     switch (cond->type)
222     {
223     case EXPR_COMPLEX:
224         return eval_binary( table, row, &cond->u.expr, val );
225     case EXPR_UNARY:
226         return eval_unary( table, row, &cond->u.expr, val );
227     case EXPR_PROPVAL:
228         return eval_propval( table, row, cond->u.propval, val );
229     case EXPR_SVAL:
230         *val = (INT_PTR)cond->u.sval;
231         return S_OK;
232     case EXPR_IVAL:
233     case EXPR_BVAL:
234         *val = cond->u.ival;
235         return S_OK;
236     default:
237         ERR("invalid expression type\n");
238         break;
239     }
240     return WBEM_E_INVALID_QUERY;
241 }
242
243 static HRESULT execute_view( struct view *view )
244 {
245     UINT i, j = 0, len;
246
247     if (!view->table || !view->table->num_rows) return S_OK;
248
249     len = min( view->table->num_rows, 16 );
250     if (!(view->result = heap_alloc( len * sizeof(UINT) ))) return E_OUTOFMEMORY;
251
252     for (i = 0; i < view->table->num_rows; i++)
253     {
254         HRESULT hr;
255         LONGLONG val = 0;
256
257         if (j >= len)
258         {
259             UINT *tmp;
260             len *= 2;
261             if (!(tmp = heap_realloc( view->result, len * sizeof(UINT) ))) return E_OUTOFMEMORY;
262             view->result = tmp;
263         }
264         if ((hr = eval_cond( view->table, i, view->cond, &val )) != S_OK) return hr;
265         if (val) view->result[j++] = i;
266     }
267     view->count = j;
268     return S_OK;
269 }
270
271 static struct query *create_query(void)
272 {
273     struct query *query;
274
275     if (!(query = heap_alloc( sizeof(*query) ))) return NULL;
276     list_init( &query->mem );
277     query->refs = 1;
278     return query;
279 }
280
281 static void free_query( struct query *query )
282 {
283     struct list *mem, *next;
284
285     destroy_view( query->view );
286     LIST_FOR_EACH_SAFE( mem, next, &query->mem )
287     {
288         heap_free( mem );
289     }
290     heap_free( query );
291 }
292
293 void addref_query( struct query *query )
294 {
295     InterlockedIncrement( &query->refs );
296 }
297
298 void release_query( struct query *query )
299 {
300     if (!InterlockedDecrement( &query->refs )) free_query( query );
301 }
302
303 HRESULT exec_query( const WCHAR *str, IEnumWbemClassObject **result )
304 {
305     HRESULT hr;
306     struct query *query;
307
308     *result = NULL;
309     if (!(query = create_query())) return E_OUTOFMEMORY;
310     hr = parse_query( str, &query->view, &query->mem );
311     if (hr != S_OK) goto done;
312     hr = execute_view( query->view );
313     if (hr != S_OK) goto done;
314     hr = EnumWbemClassObject_create( NULL, query, (void **)result );
315
316 done:
317     release_query( query );
318     return hr;
319 }
320
321 static BOOL is_selected_prop( const struct view *view, const WCHAR *name )
322 {
323     const struct property *prop = view->proplist;
324
325     if (!prop) return TRUE;
326     while (prop)
327     {
328         if (!strcmpiW( prop->name, name )) return TRUE;
329         prop = prop->next;
330     }
331     return FALSE;
332 }
333
334 static BOOL is_system_prop( const WCHAR *name )
335 {
336     return (name[0] == '_' && name[1] == '_');
337 }
338
339 static BSTR build_servername( const struct view *view )
340 {
341     WCHAR server[MAX_COMPUTERNAME_LENGTH + 1], *p;
342     DWORD len = sizeof(server)/sizeof(server[0]);
343
344     if (view->proplist) return NULL;
345
346     if (!(GetComputerNameW( server, &len ))) return NULL;
347     for (p = server; *p; p++) *p = toupperW( *p );
348     return SysAllocString( server );
349 }
350
351 static BSTR build_classname( const struct view *view )
352 {
353     return SysAllocString( view->table->name );
354 }
355
356 static BSTR build_namespace( const struct view *view )
357 {
358     static const WCHAR cimv2W[] = {'R','O','O','T','\\','C','I','M','V','2',0};
359
360     if (view->proplist) return NULL;
361     return SysAllocString( cimv2W );
362 }
363
364 static BSTR build_proplist( const struct view *view, UINT index, UINT count, UINT *len )
365 {
366     static const WCHAR fmtW[] = {'%','s','=','%','s',0};
367     UINT i, j, offset, row = view->result[index];
368     BSTR *values, ret = NULL;
369
370     if (!(values = heap_alloc( count * sizeof(BSTR) ))) return NULL;
371
372     *len = j = 0;
373     for (i = 0; i < view->table->num_cols; i++)
374     {
375         if (view->table->columns[i].type & COL_FLAG_KEY)
376         {
377             const WCHAR *name = view->table->columns[i].name;
378
379             values[j] = get_value_bstr( view->table, row, i );
380             *len += strlenW( fmtW ) + strlenW( name ) + strlenW( values[j] );
381             j++;
382         }
383     }
384     if ((ret = SysAllocStringLen( NULL, *len )))
385     {
386         offset = j = 0;
387         for (i = 0; i < view->table->num_cols; i++)
388         {
389             if (view->table->columns[i].type & COL_FLAG_KEY)
390             {
391                 const WCHAR *name = view->table->columns[i].name;
392
393                 offset += sprintfW( ret + offset, fmtW, name, values[j] );
394                 if (j < count - 1) ret[offset++] = ',';
395                 j++;
396             }
397         }
398     }
399     for (i = 0; i < count; i++) SysFreeString( values[i] );
400     heap_free( values );
401     return ret;
402 }
403
404 static UINT count_key_columns( const struct view *view )
405 {
406     UINT i, num_keys = 0;
407
408     for (i = 0; i < view->table->num_cols; i++)
409     {
410         if (view->table->columns[i].type & COL_FLAG_KEY) num_keys++;
411     }
412     return num_keys;
413 }
414
415 static BSTR build_relpath( const struct view *view, UINT index, const WCHAR *name )
416 {
417     static const WCHAR fmtW[] = {'%','s','.','%','s',0};
418     BSTR class, proplist, ret = NULL;
419     UINT num_keys, len;
420
421     if (view->proplist) return NULL;
422
423     if (!(class = build_classname( view ))) return NULL;
424     if (!(num_keys = count_key_columns( view ))) return class;
425     if (!(proplist = build_proplist( view, index, num_keys, &len ))) goto done;
426
427     len += strlenW( fmtW ) + SysStringLen( class );
428     if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
429     sprintfW( ret, fmtW, class, proplist );
430
431 done:
432     SysFreeString( class );
433     SysFreeString( proplist );
434     return ret;
435 }
436
437 static BSTR build_path( const struct view *view, UINT index, const WCHAR *name )
438 {
439     static const WCHAR fmtW[] = {'\\','\\','%','s','\\','%','s',':','%','s',0};
440     BSTR server, namespace = NULL, relpath = NULL, ret = NULL;
441     UINT len;
442
443     if (view->proplist) return NULL;
444
445     if (!(server = build_servername( view ))) return NULL;
446     if (!(namespace = build_namespace( view ))) goto done;
447     if (!(relpath = build_relpath( view, index, name ))) goto done;
448
449     len = strlenW( fmtW ) + SysStringLen( server ) + SysStringLen( namespace ) + SysStringLen( relpath );
450     if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
451     sprintfW( ret, fmtW, server, namespace, relpath );
452
453 done:
454     SysFreeString( server );
455     SysFreeString( namespace );
456     SysFreeString( relpath );
457     return ret;
458 }
459
460 static inline BOOL is_method( const struct table *table, UINT column )
461 {
462     return table->columns[column].type & COL_FLAG_METHOD;
463 }
464
465 static UINT count_properties( const struct view *view )
466 {
467     UINT i, num_props = 0;
468
469     for (i = 0; i < view->table->num_cols; i++)
470     {
471         if (!is_method( view->table, i)) num_props++;
472     }
473     return num_props;
474 }
475
476 static UINT count_selected_properties( const struct view *view )
477 {
478     const struct property *prop = view->proplist;
479     UINT count;
480
481     if (!prop) return count_properties( view );
482
483     count = 1;
484     while ((prop = prop->next)) count++;
485     return count;
486 }
487
488 static HRESULT get_system_propval( const struct view *view, UINT index, const WCHAR *name,
489                                    VARIANT *ret, CIMTYPE *type, LONG *flavor )
490 {
491     static const WCHAR classW[] = {'_','_','C','L','A','S','S',0};
492     static const WCHAR genusW[] = {'_','_','G','E','N','U','S',0};
493     static const WCHAR pathW[] = {'_','_','P','A','T','H',0};
494     static const WCHAR namespaceW[] = {'_','_','N','A','M','E','S','P','A','C','E',0};
495     static const WCHAR propcountW[] = {'_','_','P','R','O','P','E','R','T','Y','_','C','O','U','N','T',0};
496     static const WCHAR relpathW[] = {'_','_','R','E','L','P','A','T','H',0};
497     static const WCHAR serverW[] = {'_','_','S','E','R','V','E','R',0};
498
499     if (flavor) *flavor = WBEM_FLAVOR_ORIGIN_SYSTEM;
500
501     if (!strcmpiW( name, classW ))
502     {
503         V_VT( ret ) = VT_BSTR;
504         V_BSTR( ret ) = build_classname( view );
505         if (type) *type = CIM_STRING;
506         return S_OK;
507     }
508     if (!strcmpiW( name, genusW ))
509     {
510         V_VT( ret ) = VT_I4;
511         V_I4( ret ) = WBEM_GENUS_INSTANCE; /* FIXME */
512         if (type) *type = CIM_SINT32;
513         return S_OK;
514     }
515     else if (!strcmpiW( name, namespaceW ))
516     {
517         V_VT( ret ) = VT_BSTR;
518         V_BSTR( ret ) = build_namespace( view );
519         if (type) *type = CIM_STRING;
520         return S_OK;
521     }
522     else if (!strcmpiW( name, pathW ))
523     {
524         V_VT( ret ) = VT_BSTR;
525         V_BSTR( ret ) = build_path( view, index, name );
526         if (type) *type = CIM_STRING;
527         return S_OK;
528     }
529     if (!strcmpiW( name, propcountW ))
530     {
531         V_VT( ret ) = VT_I4;
532         V_I4( ret ) = count_selected_properties( view );
533         if (type) *type = CIM_SINT32;
534         return S_OK;
535     }
536     else if (!strcmpiW( name, relpathW ))
537     {
538         V_VT( ret ) = VT_BSTR;
539         V_BSTR( ret ) = build_relpath( view, index, name );
540         if (type) *type = CIM_STRING;
541         return S_OK;
542     }
543     else if (!strcmpiW( name, serverW ))
544     {
545         V_VT( ret ) = VT_BSTR;
546         V_BSTR( ret ) = build_servername( view );
547         if (type) *type = CIM_STRING;
548         return S_OK;
549     }
550     FIXME("system property %s not implemented\n", debugstr_w(name));
551     return WBEM_E_NOT_FOUND;
552 }
553
554 VARTYPE to_vartype( CIMTYPE type )
555 {
556     switch (type)
557     {
558     case CIM_BOOLEAN:  return VT_BOOL;
559     case CIM_STRING:
560     case CIM_DATETIME: return VT_BSTR;
561     case CIM_SINT16:   return VT_I2;
562     case CIM_UINT16:   return VT_UI2;
563     case CIM_SINT32:   return VT_I4;
564     case CIM_UINT32:   return VT_UI4;
565     case CIM_SINT64:   return VT_I8;
566     case CIM_UINT64:   return VT_UI8;
567     default:
568         ERR("unhandled type %u\n", type);
569         break;
570     }
571     return 0;
572 }
573
574 SAFEARRAY *to_safearray( const struct array *array, CIMTYPE type )
575 {
576     SAFEARRAY *ret;
577     UINT size = get_type_size( type );
578     VARTYPE vartype = to_vartype( type );
579     LONG i;
580
581     if (!(ret = SafeArrayCreateVector( vartype, 0, array->count ))) return NULL;
582
583     for (i = 0; i < array->count; i++)
584     {
585         void *ptr = (char *)array->ptr + i * size;
586         if (vartype == VT_BSTR)
587         {
588             BSTR str = SysAllocString( *(const WCHAR **)ptr );
589             if (!str || SafeArrayPutElement( ret, &i, str ) != S_OK)
590             {
591                 SysFreeString( str );
592                 SafeArrayDestroy( ret );
593                 return NULL;
594             }
595         }
596         else if (SafeArrayPutElement( ret, &i, ptr ) != S_OK)
597         {
598             SafeArrayDestroy( ret );
599             return NULL;
600         }
601     }
602     return ret;
603 }
604
605 static void set_variant( VARTYPE type, LONGLONG val, void *val_ptr, VARIANT *ret )
606 {
607     if (type & VT_ARRAY)
608     {
609         V_VT( ret ) = type;
610         V_ARRAY( ret ) = val_ptr;
611         return;
612     }
613     switch (type)
614     {
615     case VT_BOOL:
616         V_BOOL( ret ) = val;
617         break;
618     case VT_BSTR:
619         V_BSTR( ret ) = val_ptr;
620         break;
621     case VT_I2:
622         V_I2( ret ) = val;
623         break;
624     case VT_UI2:
625         V_UI2( ret ) = val;
626         break;
627     case VT_I4:
628         V_I4( ret ) = val;
629         break;
630     case VT_UI4:
631         V_UI4( ret ) = val;
632         break;
633     case VT_NULL:
634         break;
635     default:
636         ERR("unhandled variant type %u\n", type);
637         return;
638     }
639     V_VT( ret ) = type;
640 }
641
642 #define CIM_TYPE_MASK 0xfff
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 = view->result[index];
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 (!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     vartype = view->table->columns[column].vartype;
660
661     hr = get_value( view->table, row, column, &val );
662     if (hr != S_OK) return hr;
663
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( ret->count * size )))
754     {
755         heap_free( ret );
756         return NULL;
757     }
758     for (i = 0; i < ret->count; i++)
759     {
760         if (SafeArrayGetElement( V_ARRAY( var ), &i, (char *)ret->ptr + i * size ) != S_OK)
761         {
762             if (vartype == VT_BSTR)
763                 for (i--; i >= 0; i--) SysFreeString( *(BSTR *)(char *)ret->ptr + i * size );
764             heap_free( ret->ptr );
765             heap_free( ret );
766             return NULL;
767         }
768     }
769     *type = basetype | CIM_FLAG_ARRAY;
770     return ret;
771 }
772
773 HRESULT to_longlong( VARIANT *var, LONGLONG *val, CIMTYPE *type )
774 {
775     if (!var)
776     {
777         *val = 0;
778         return S_OK;
779     }
780     if (V_VT( var ) & VT_ARRAY)
781     {
782         *val = (INT_PTR)to_array( var, type );
783         if (!*val) return E_OUTOFMEMORY;
784         return S_OK;
785     }
786     switch (V_VT( var ))
787     {
788     case VT_BOOL:
789         *val = V_BOOL( var );
790         *type = CIM_BOOLEAN;
791         break;
792     case VT_BSTR:
793         *val = (INT_PTR)SysAllocString( V_BSTR( var ) );
794         if (!*val) return E_OUTOFMEMORY;
795         *type = CIM_STRING;
796         break;
797     case VT_I2:
798         *val = V_I2( var );
799         *type = CIM_SINT16;
800         break;
801     case VT_UI2:
802         *val = V_UI2( var );
803         *type = CIM_UINT16;
804         break;
805     case VT_I4:
806         *val = V_I4( var );
807         *type = CIM_SINT32;
808         break;
809     case VT_UI4:
810         *val = V_UI4( var );
811         *type = CIM_UINT32;
812         break;
813     case VT_NULL:
814         *val = 0;
815         break;
816     default:
817         ERR("unhandled type %u\n", V_VT( var ));
818         return WBEM_E_FAILED;
819     }
820     return S_OK;
821 }
822
823 HRESULT put_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *var, CIMTYPE type )
824 {
825     HRESULT hr;
826     UINT column, row = view->result[index];
827     LONGLONG val;
828
829     hr = get_column_index( view->table, name, &column );
830     if (hr != S_OK)
831     {
832         FIXME("no support for creating new properties\n");
833         return WBEM_E_FAILED;
834     }
835     if (is_method( view->table, column ) || !(view->table->columns[column].type & COL_FLAG_DYNAMIC))
836         return WBEM_E_FAILED;
837
838     hr = to_longlong( var, &val, &type );
839     if (hr != S_OK) return hr;
840
841     return set_value( view->table, row, column, val, type );
842 }
843
844 HRESULT get_properties( const struct view *view, SAFEARRAY **props )
845 {
846     SAFEARRAY *sa;
847     BSTR str;
848     LONG i;
849     UINT num_props = count_properties( view );
850
851     if (!(sa = SafeArrayCreateVector( VT_BSTR, 0, num_props ))) return E_OUTOFMEMORY;
852
853     for (i = 0; i < view->table->num_cols; i++)
854     {
855         if (is_method( view->table, i )) continue;
856
857         str = SysAllocString( view->table->columns[i].name );
858         if (!str || SafeArrayPutElement( sa, &i, str ) != S_OK)
859         {
860             SysFreeString( str );
861             SafeArrayDestroy( sa );
862             return E_OUTOFMEMORY;
863         }
864     }
865     *props = sa;
866     return S_OK;
867 }