Release 1.5.29.
[wine] / dlls / wbemprox / table.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 get_column_index( const struct table *table, const WCHAR *name, UINT *column )
34 {
35     UINT i;
36     for (i = 0; i < table->num_cols; i++)
37     {
38         if (!strcmpiW( table->columns[i].name, name ))
39         {
40             *column = i;
41             return S_OK;
42         }
43     }
44     return WBEM_E_INVALID_QUERY;
45 }
46
47 UINT get_type_size( CIMTYPE type )
48 {
49     if (type & CIM_FLAG_ARRAY) return sizeof(void *);
50
51     switch (type)
52     {
53     case CIM_BOOLEAN:
54         return sizeof(int);
55     case CIM_SINT16:
56     case CIM_UINT16:
57         return sizeof(INT16);
58     case CIM_SINT32:
59     case CIM_UINT32:
60         return sizeof(INT32);
61     case CIM_SINT64:
62     case CIM_UINT64:
63         return sizeof(INT64);
64     case CIM_DATETIME:
65     case CIM_STRING:
66         return sizeof(WCHAR *);
67     default:
68         ERR("unhandled type %u\n", type);
69         break;
70     }
71     return sizeof(LONGLONG);
72 }
73
74 static UINT get_column_size( const struct table *table, UINT column )
75 {
76     return get_type_size( table->columns[column].type & COL_TYPE_MASK );
77 }
78
79 static UINT get_column_offset( const struct table *table, UINT column )
80 {
81     UINT i, offset = 0;
82     for (i = 0; i < column; i++) offset += get_column_size( table, i );
83     return offset;
84 }
85
86 static UINT get_row_size( const struct table *table )
87 {
88     return get_column_offset( table, table->num_cols - 1 ) + get_column_size( table, table->num_cols - 1 );
89 }
90
91 HRESULT get_value( const struct table *table, UINT row, UINT column, LONGLONG *val )
92 {
93     UINT col_offset, row_size;
94     const BYTE *ptr;
95
96     col_offset = get_column_offset( table, column );
97     row_size = get_row_size( table );
98     ptr = table->data + row * row_size + col_offset;
99
100     if (table->columns[column].type & CIM_FLAG_ARRAY)
101     {
102         *val = (INT_PTR)*(const void **)ptr;
103         return S_OK;
104     }
105     switch (table->columns[column].type & COL_TYPE_MASK)
106     {
107     case CIM_BOOLEAN:
108         *val = *(const int *)ptr;
109         break;
110     case CIM_DATETIME:
111     case CIM_STRING:
112         *val = (INT_PTR)*(const WCHAR **)ptr;
113         break;
114     case CIM_SINT16:
115         *val = *(const INT16 *)ptr;
116         break;
117     case CIM_UINT16:
118         *val = *(const UINT16 *)ptr;
119         break;
120     case CIM_SINT32:
121         *val = *(const INT32 *)ptr;
122         break;
123     case CIM_UINT32:
124         *val = *(const UINT32 *)ptr;
125         break;
126     case CIM_SINT64:
127         *val = *(const INT64 *)ptr;
128         break;
129     case CIM_UINT64:
130         *val = *(const UINT64 *)ptr;
131         break;
132     default:
133         ERR("invalid column type %u\n", table->columns[column].type & COL_TYPE_MASK);
134         *val = 0;
135         break;
136     }
137     return S_OK;
138 }
139
140 BSTR get_value_bstr( const struct table *table, UINT row, UINT column )
141 {
142     static const WCHAR fmt_signedW[] = {'%','d',0};
143     static const WCHAR fmt_unsignedW[] = {'%','u',0};
144     static const WCHAR fmt_signed64W[] = {'%','I','6','4','d',0};
145     static const WCHAR fmt_unsigned64W[] = {'%','I','6','4','u',0};
146     static const WCHAR fmt_strW[] = {'\"','%','s','\"',0};
147     static const WCHAR trueW[] = {'T','R','U','E',0};
148     static const WCHAR falseW[] = {'F','A','L','S','E',0};
149     LONGLONG val;
150     BSTR ret;
151     WCHAR number[22];
152     UINT len;
153
154     if (table->columns[column].type & CIM_FLAG_ARRAY)
155     {
156         FIXME("array to string conversion not handled\n");
157         return NULL;
158     }
159     if (get_value( table, row, column, &val ) != S_OK) return NULL;
160
161     switch (table->columns[column].type & COL_TYPE_MASK)
162     {
163     case CIM_BOOLEAN:
164         if (val) return SysAllocString( trueW );
165         else return SysAllocString( falseW );
166
167     case CIM_DATETIME:
168     case CIM_STRING:
169         if (!val) return NULL;
170         len = strlenW( (const WCHAR *)(INT_PTR)val ) + 2;
171         if (!(ret = SysAllocStringLen( NULL, len ))) return NULL;
172         sprintfW( ret, fmt_strW, (const WCHAR *)(INT_PTR)val );
173         return ret;
174
175     case CIM_SINT16:
176     case CIM_SINT32:
177         sprintfW( number, fmt_signedW, val );
178         return SysAllocString( number );
179
180     case CIM_UINT16:
181     case CIM_UINT32:
182         sprintfW( number, fmt_unsignedW, val );
183         return SysAllocString( number );
184
185     case CIM_SINT64:
186         wsprintfW( number, fmt_signed64W, val );
187         return SysAllocString( number );
188
189     case CIM_UINT64:
190         wsprintfW( number, fmt_unsigned64W, val );
191         return SysAllocString( number );
192
193     default:
194         FIXME("unhandled column type %u\n", table->columns[column].type & COL_TYPE_MASK);
195         break;
196     }
197     return NULL;
198 }
199
200 HRESULT set_value( const struct table *table, UINT row, UINT column, LONGLONG val,
201                    CIMTYPE type )
202 {
203     UINT col_offset, row_size;
204     BYTE *ptr;
205
206     if ((table->columns[column].type & COL_TYPE_MASK) != type) return WBEM_E_TYPE_MISMATCH;
207
208     col_offset = get_column_offset( table, column );
209     row_size = get_row_size( table );
210     ptr = table->data + row * row_size + col_offset;
211
212     switch (table->columns[column].type & COL_TYPE_MASK)
213     {
214     case CIM_DATETIME:
215     case CIM_STRING:
216         *(WCHAR **)ptr = (WCHAR *)(INT_PTR)val;
217         break;
218     case CIM_SINT16:
219         *(INT16 *)ptr = val;
220         break;
221     case CIM_UINT16:
222         *(UINT16 *)ptr = val;
223         break;
224     case CIM_SINT32:
225         *(INT32 *)ptr = val;
226         break;
227     case CIM_UINT32:
228         *(UINT32 *)ptr = val;
229         break;
230     case CIM_SINT64:
231         *(INT64 *)ptr = val;
232         break;
233     case CIM_UINT64:
234         *(UINT64 *)ptr = val;
235         break;
236     default:
237         FIXME("unhandled column type %u\n", type);
238         return WBEM_E_FAILED;
239     }
240     return S_OK;
241 }
242
243 HRESULT get_method( const struct table *table, const WCHAR *name, class_method **func )
244 {
245     UINT i, j;
246
247     for (i = 0; i < table->num_rows; i++)
248     {
249         for (j = 0; j < table->num_cols; j++)
250         {
251             if (table->columns[j].type & COL_FLAG_METHOD && !strcmpW( table->columns[j].name, name ))
252             {
253                 HRESULT hr;
254                 LONGLONG val;
255
256                 if ((hr = get_value( table, i, j, &val )) != S_OK) return hr;
257                 *func = (class_method *)(INT_PTR)val;
258                 return S_OK;
259             }
260         }
261     }
262     return WBEM_E_INVALID_METHOD;
263
264 }
265
266 static void clear_table( struct table *table )
267 {
268     UINT i, j, type;
269     LONGLONG val;
270
271     if (!table->data) return;
272
273     for (i = 0; i < table->num_rows; i++)
274     {
275         for (j = 0; j < table->num_cols; j++)
276         {
277             if (!(table->columns[j].type & COL_FLAG_DYNAMIC)) continue;
278
279             type = table->columns[j].type & COL_TYPE_MASK;
280             if (type == CIM_STRING || type == CIM_DATETIME || (type & CIM_FLAG_ARRAY))
281             {
282                 if (get_value( table, i, j, &val ) == S_OK) heap_free( (void *)(INT_PTR)val );
283             }
284         }
285     }
286     if (table->fill)
287     {
288         table->num_rows = 0;
289         heap_free( table->data );
290         table->data = NULL;
291     }
292 }
293
294 void free_columns( struct column *columns, UINT num_cols )
295 {
296     UINT i;
297
298     for (i = 0; i < num_cols; i++)
299     {
300         heap_free( (WCHAR *)columns[i].name );
301     }
302     heap_free( columns );
303 }
304
305 void free_table( struct table *table )
306 {
307     if (!table) return;
308
309     clear_table( table );
310     if (table->flags & TABLE_FLAG_DYNAMIC)
311     {
312         TRACE("destroying %p\n", table);
313         heap_free( (WCHAR *)table->name );
314         free_columns( (struct column *)table->columns, table->num_cols );
315         list_remove( &table->entry );
316         heap_free( table );
317     }
318 }
319
320 void release_table( struct table *table )
321 {
322     if (!InterlockedDecrement( &table->refs )) free_table( table );
323 }
324
325 struct table *addref_table( struct table *table )
326 {
327     InterlockedIncrement( &table->refs );
328     return table;
329 }
330
331 struct table *grab_table( const WCHAR *name )
332 {
333     struct table *table;
334
335     LIST_FOR_EACH_ENTRY( table, table_list, struct table, entry )
336     {
337         if (!strcmpiW( table->name, name ))
338         {
339             if (table->fill && !table->data) table->fill( table );
340             TRACE("returning %p\n", table);
341             return addref_table( table );
342         }
343     }
344     return NULL;
345 }
346
347 struct table *create_table( const WCHAR *name, UINT num_cols, const struct column *columns,
348                             UINT num_rows, BYTE *data, void (*fill)(struct table *) )
349 {
350     struct table *table;
351
352     if (!(table = heap_alloc( sizeof(*table) ))) return NULL;
353     table->name     = heap_strdupW( name );
354     table->num_cols = num_cols;
355     table->columns  = columns;
356     table->num_rows = num_rows;
357     table->data     = data;
358     table->fill     = fill;
359     table->flags    = TABLE_FLAG_DYNAMIC;
360     table->refs     = 0;
361     list_init( &table->entry );
362     return table;
363 }
364
365 BOOL add_table( struct table *table )
366 {
367     struct table *iter;
368
369     LIST_FOR_EACH_ENTRY( iter, table_list, struct table, entry )
370     {
371         if (!strcmpiW( iter->name, table->name ))
372         {
373             TRACE("table %s already exists\n", debugstr_w(table->name));
374             return FALSE;
375         }
376     }
377     list_add_tail( table_list, &table->entry );
378     TRACE("added %p\n", table);
379     return TRUE;
380 }
381
382 BSTR get_method_name( const WCHAR *class, UINT index )
383 {
384     struct table *table;
385     UINT i, count = 0;
386     BSTR ret;
387
388     if (!(table = grab_table( class ))) return NULL;
389
390     for (i = 0; i < table->num_cols; i++)
391     {
392         if (table->columns[i].type & COL_FLAG_METHOD)
393         {
394             if (index == count)
395             {
396                 ret = SysAllocString( table->columns[i].name );
397                 release_table( table );
398                 return ret;
399             }
400             count++;
401         }
402     }
403     release_table( table );
404     return NULL;
405 }
406
407 BSTR get_property_name( const WCHAR *class, UINT index )
408 {
409     struct table *table;
410     UINT i, count = 0;
411     BSTR ret;
412
413     if (!(table = grab_table( class ))) return NULL;
414
415     for (i = 0; i < table->num_cols; i++)
416     {
417         if (!(table->columns[i].type & COL_FLAG_METHOD))
418         {
419             if (index == count)
420             {
421                 ret = SysAllocString( table->columns[i].name );
422                 release_table( table );
423                 return ret;
424             }
425             count++;
426         }
427     }
428     release_table( table );
429     return NULL;
430 }