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