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