wbemprox: Add reference counting to the table structure.
[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 = (LONGLONG)(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 = (LONGLONG)(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         len = strlenW( (const WCHAR *)(INT_PTR)val ) + 2;
170         if (!(ret = SysAllocStringLen( NULL, len ))) return NULL;
171         sprintfW( ret, fmt_strW, (const WCHAR *)(INT_PTR)val );
172         return ret;
173
174     case CIM_SINT16:
175     case CIM_SINT32:
176         sprintfW( number, fmt_signedW, val );
177         return SysAllocString( number );
178
179     case CIM_UINT16:
180     case CIM_UINT32:
181         sprintfW( number, fmt_unsignedW, val );
182         return SysAllocString( number );
183
184     case CIM_SINT64:
185         wsprintfW( number, fmt_signed64W, val );
186         return SysAllocString( number );
187
188     case CIM_UINT64:
189         wsprintfW( number, fmt_unsigned64W, val );
190         return SysAllocString( number );
191
192     default:
193         FIXME("unhandled column type %u\n", table->columns[column].type & COL_TYPE_MASK);
194         break;
195     }
196     return NULL;
197 }
198
199 HRESULT set_value( const struct table *table, UINT row, UINT column, LONGLONG val,
200                    CIMTYPE type )
201 {
202     UINT col_offset, row_size;
203     BYTE *ptr;
204
205     if ((table->columns[column].type & COL_TYPE_MASK) != type) return WBEM_E_TYPE_MISMATCH;
206
207     col_offset = get_column_offset( table, column );
208     row_size = get_row_size( table );
209     ptr = table->data + row * row_size + col_offset;
210
211     switch (table->columns[column].type & COL_TYPE_MASK)
212     {
213     case CIM_DATETIME:
214     case CIM_STRING:
215         *(WCHAR **)ptr = (WCHAR *)(INT_PTR)val;
216         break;
217     case CIM_SINT16:
218         *(INT16 *)ptr = val;
219         break;
220     case CIM_UINT16:
221         *(UINT16 *)ptr = val;
222         break;
223     case CIM_SINT32:
224         *(INT32 *)ptr = val;
225         break;
226     case CIM_UINT32:
227         *(UINT32 *)ptr = val;
228         break;
229     case CIM_SINT64:
230         *(INT64 *)ptr = val;
231         break;
232     case CIM_UINT64:
233         *(UINT64 *)ptr = val;
234         break;
235     default:
236         FIXME("unhandled column type %u\n", type);
237         return WBEM_E_FAILED;
238     }
239     return S_OK;
240 }
241
242 HRESULT get_method( const struct table *table, const WCHAR *name, class_method **func )
243 {
244     UINT i, j;
245
246     for (i = 0; i < table->num_rows; i++)
247     {
248         for (j = 0; j < table->num_cols; j++)
249         {
250             if (table->columns[j].type & COL_FLAG_METHOD && !strcmpW( table->columns[j].name, name ))
251             {
252                 HRESULT hr;
253                 LONGLONG val;
254
255                 if ((hr = get_value( table, i, j, &val )) != S_OK) return hr;
256                 *func = (class_method *)(INT_PTR)val;
257                 return S_OK;
258             }
259         }
260     }
261     return WBEM_E_INVALID_METHOD;
262
263 }
264
265 static void clear_table( struct table *table )
266 {
267     UINT i, j, type;
268     LONGLONG val;
269
270     if (!table->data) return;
271
272     for (i = 0; i < table->num_rows; i++)
273     {
274         for (j = 0; j < table->num_cols; j++)
275         {
276             if (!(table->columns[j].type & COL_FLAG_DYNAMIC)) continue;
277
278             type = table->columns[j].type & COL_TYPE_MASK;
279             if (type == CIM_STRING || type == CIM_DATETIME || (type & CIM_FLAG_ARRAY))
280             {
281                 if (get_value( table, i, j, &val ) == S_OK) heap_free( (void *)(INT_PTR)val );
282             }
283         }
284     }
285     if (table->fill)
286     {
287         table->num_rows = 0;
288         heap_free( table->data );
289         table->data = NULL;
290     }
291 }
292
293 void free_columns( struct column *columns, UINT num_cols )
294 {
295     UINT i;
296
297     for (i = 0; i < num_cols; i++)
298     {
299         heap_free( (WCHAR *)columns[i].name );
300     }
301     heap_free( columns );
302 }
303
304 void free_table( struct table *table )
305 {
306     if (!table) return;
307
308     clear_table( table );
309     if (table->flags & TABLE_FLAG_DYNAMIC)
310     {
311         TRACE("destroying %p\n", table);
312         heap_free( (WCHAR *)table->name );
313         free_columns( (struct column *)table->columns, table->num_cols );
314         list_remove( &table->entry );
315         heap_free( table );
316     }
317 }
318
319 void release_table( struct table *table )
320 {
321     if (!InterlockedDecrement( &table->refs )) free_table( table );
322 }
323
324 struct table *grab_table( const WCHAR *name )
325 {
326     struct table *table;
327
328     LIST_FOR_EACH_ENTRY( table, table_list, struct table, entry )
329     {
330         if (!strcmpiW( table->name, name ))
331         {
332             if (table->fill && !table->data) table->fill( table );
333             InterlockedIncrement( &table->refs );
334             TRACE("returning %p\n", table);
335             return table;
336         }
337     }
338     return NULL;
339 }
340
341 struct table *create_table( const WCHAR *name, UINT num_cols, const struct column *columns,
342                             UINT num_rows, BYTE *data, void (*fill)(struct table *) )
343 {
344     struct table *table;
345
346     if (!(table = heap_alloc( sizeof(*table) ))) return NULL;
347     table->name     = heap_strdupW( name );
348     table->num_cols = num_cols;
349     table->columns  = columns;
350     table->num_rows = num_rows;
351     table->data     = data;
352     table->fill     = fill;
353     table->flags    = TABLE_FLAG_DYNAMIC;
354     table->refs     = 0;
355     list_init( &table->entry );
356     return table;
357 }
358
359 BOOL add_table( struct table *table )
360 {
361     struct table *iter;
362
363     LIST_FOR_EACH_ENTRY( iter, table_list, struct table, entry )
364     {
365         if (!strcmpiW( iter->name, table->name ))
366         {
367             TRACE("table %s already exists\n", debugstr_w(table->name));
368             return FALSE;
369         }
370     }
371     list_add_tail( table_list, &table->entry );
372     TRACE("added %p\n", table);
373     return TRUE;
374 }
375
376 BSTR get_method_name( const WCHAR *class, UINT index )
377 {
378     struct table *table;
379     UINT i, count = 0;
380     BSTR ret;
381
382     if (!(table = grab_table( class ))) return NULL;
383
384     for (i = 0; i < table->num_cols; i++)
385     {
386         if (table->columns[i].type & COL_FLAG_METHOD)
387         {
388             if (index == count)
389             {
390                 ret = SysAllocString( table->columns[i].name );
391                 release_table( table );
392                 return ret;
393             }
394             count++;
395         }
396     }
397     release_table( table );
398     return NULL;
399 }
400
401 BSTR get_property_name( const WCHAR *class, UINT index )
402 {
403     struct table *table;
404     UINT i, count = 0;
405     BSTR ret;
406
407     if (!(table = grab_table( class ))) return NULL;
408
409     for (i = 0; i < table->num_cols; i++)
410     {
411         if (!(table->columns[i].type & COL_FLAG_METHOD))
412         {
413             if (index == count)
414             {
415                 ret = SysAllocString( table->columns[i].name );
416                 release_table( table );
417                 return ret;
418             }
419             count++;
420         }
421     }
422     release_table( table );
423     return NULL;
424 }