Implement A->W call for GetNamedSecurityInfo.
[wine] / dlls / msi / record.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2002-2004 Mike McCormack for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "winerror.h"
27 #include "wine/debug.h"
28 #include "msi.h"
29 #include "msiquery.h"
30 #include "msipriv.h"
31 #include "objidl.h"
32 #include "winnls.h"
33
34 #include "query.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(msi);
37
38 #define MSIFIELD_NULL   0
39 #define MSIFIELD_INT    1
40 #define MSIFIELD_STR    2
41 #define MSIFIELD_WSTR   3
42 #define MSIFIELD_STREAM 4
43
44 void MSI_FreeField( MSIFIELD *field )
45 {
46     switch( field->type )
47     {
48     case MSIFIELD_NULL:
49     case MSIFIELD_INT:
50         break;
51     case MSIFIELD_WSTR:
52         HeapFree( GetProcessHeap(), 0, field->u.szwVal);
53         break;
54     case MSIFIELD_STREAM:
55         IStream_Release( field->u.stream );
56         break;
57     default:
58         ERR("Invalid field type %d\n", field->type);
59     }
60 }
61
62 void MSI_CloseRecord( MSIOBJECTHDR *arg )
63 {
64     MSIRECORD *rec = (MSIRECORD *) arg;
65     UINT i;
66
67     for( i=0; i<=rec->count; i++ )
68         MSI_FreeField( &rec->fields[i] );
69 }
70
71 MSIRECORD *MSI_CreateRecord( unsigned int cParams )
72 {
73     MSIRECORD *rec;
74     UINT len;
75
76     TRACE("%d\n", cParams);
77
78     len = sizeof (MSIRECORD) + sizeof (MSIFIELD)*cParams;
79     rec = alloc_msiobject( MSIHANDLETYPE_RECORD, len, MSI_CloseRecord );
80     if( rec )
81     rec->count = cParams;
82     return rec;
83 }
84
85 MSIHANDLE WINAPI MsiCreateRecord( unsigned int cParams )
86 {
87     MSIRECORD *rec;
88     MSIHANDLE ret = 0;
89
90     TRACE("%d\n", cParams);
91
92     rec = MSI_CreateRecord( cParams );
93     if( rec )
94         ret = alloc_msihandle( &rec->hdr );
95     return ret;
96 }
97
98 unsigned int MSI_RecordGetFieldCount( MSIRECORD *rec )
99 {
100     return rec->count;
101 }
102
103 unsigned int WINAPI MsiRecordGetFieldCount( MSIHANDLE handle )
104 {
105     MSIRECORD *rec;
106     UINT ret;
107
108     TRACE("%ld\n", handle );
109
110     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
111     if( !rec )
112     {
113         ERR("Record not found!\n");
114         return 0;
115     }
116
117     ret = MSI_RecordGetFieldCount( rec );
118     msiobj_release( &rec->hdr );
119
120     return ret;
121 }
122
123 static BOOL string2intW( LPCWSTR str, int *out )
124 {
125     int x = 0;
126     LPCWSTR p = str;
127
128     if( *p == '-' ) /* skip the minus sign */
129         p++;
130     while ( *p )
131     {
132         if( (*p < '0') || (*p > '9') )
133             return FALSE;
134         x *= 10;
135         x += (*p - '0');
136         p++;
137     }
138
139     if( str[0] == '-' ) /* check if it's negative */
140         x = -x;
141     *out = x; 
142
143     return TRUE;
144 }
145
146 int MSI_RecordGetInteger( MSIRECORD *rec, unsigned int iField)
147 {
148     int ret = 0;
149
150     TRACE("%p %d\n", rec, iField );
151
152     if( iField > rec->count )
153         return MSI_NULL_INTEGER;
154
155     switch( rec->fields[iField].type )
156     {
157     case MSIFIELD_INT:
158         return rec->fields[iField].u.iVal;
159     case MSIFIELD_WSTR:
160         if( string2intW( rec->fields[iField].u.szwVal, &ret ) )
161             return ret;
162         return MSI_NULL_INTEGER;
163     default:
164         break;
165     }
166
167     return MSI_NULL_INTEGER;
168 }
169
170 int WINAPI MsiRecordGetInteger( MSIHANDLE handle, unsigned int iField)
171 {
172     MSIRECORD *rec;
173     UINT ret;
174
175     TRACE("%ld %d\n", handle, iField );
176
177     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
178     if( !rec )
179         return MSI_NULL_INTEGER;
180
181     ret = MSI_RecordGetInteger( rec, iField );
182     msiobj_release( &rec->hdr );
183
184     return ret;
185 }
186
187 UINT WINAPI MsiRecordClearData( MSIHANDLE handle )
188 {
189     MSIRECORD *rec;
190     UINT i;
191
192     TRACE("%ld\n", handle );
193
194     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
195     if( !rec )
196         return ERROR_INVALID_HANDLE;
197
198     for( i=0; i<=rec->count; i++)
199     {
200         MSI_FreeField( &rec->fields[i] );
201         rec->fields[i].type = MSIFIELD_NULL;
202         rec->fields[i].u.iVal = 0;
203     }
204
205     return ERROR_SUCCESS;
206 }
207
208 UINT MSI_RecordSetInteger( MSIRECORD *rec, unsigned int iField, int iVal )
209 {
210     TRACE("%p %u %d\n", rec, iField, iVal);
211
212     if( iField <= rec->count )
213     {
214         MSI_FreeField( &rec->fields[iField] );
215         rec->fields[iField].type = MSIFIELD_INT;
216         rec->fields[iField].u.iVal = iVal;
217     }
218
219     return ERROR_SUCCESS;
220 }
221
222 UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, unsigned int iField, int iVal )
223 {
224     MSIRECORD *rec;
225     UINT ret;
226
227     TRACE("%ld %u %d\n", handle, iField, iVal);
228
229     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
230     if( !rec )
231         return ERROR_INVALID_HANDLE;
232
233     ret = MSI_RecordSetInteger( rec, iField, iVal );
234     msiobj_release( &rec->hdr );
235     return ret;
236 }
237
238 BOOL MSI_RecordIsNull( MSIRECORD *rec, unsigned int iField )
239 {
240     BOOL r = TRUE;
241
242     TRACE("%p %d\n", rec, iField );
243
244     r = ( iField > rec->count ) ||
245         ( rec->fields[iField].type == MSIFIELD_NULL );
246
247     return r;
248 }
249
250 BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, unsigned int iField )
251 {
252     MSIRECORD *rec;
253     UINT ret;
254
255     TRACE("%ld %d\n", handle, iField );
256
257     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
258     if( !rec )
259         return ERROR_INVALID_HANDLE;
260     ret = MSI_RecordIsNull( rec, iField );
261     msiobj_release( &rec->hdr );
262     return ret;
263
264 }
265
266 UINT MSI_RecordGetStringA(MSIRECORD *rec, unsigned int iField, 
267                LPSTR szValue, DWORD *pcchValue)
268 {
269     UINT len=0, ret;
270     CHAR buffer[16];
271
272     TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
273
274     if( iField > rec->count )
275         return ERROR_INVALID_PARAMETER;
276
277     ret = ERROR_SUCCESS;
278     switch( rec->fields[iField].type )
279     {
280     case MSIFIELD_INT:
281         wsprintfA(buffer, "%d", rec->fields[iField].u.iVal);
282         len = lstrlenA( buffer );
283         lstrcpynA(szValue, buffer, *pcchValue);
284         break;
285     case MSIFIELD_WSTR:
286         len = WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1,
287                              NULL, 0 , NULL, NULL);
288         WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1,
289                              szValue, *pcchValue, NULL, NULL);
290         break;
291     case MSIFIELD_NULL:
292         len = 1;
293         if( *pcchValue > 0 )
294             szValue[0] = 0;
295     default:
296         ret = ERROR_INVALID_PARAMETER;
297         break;
298     }
299
300     if( *pcchValue < len )
301         ret = ERROR_MORE_DATA;
302     *pcchValue = len;
303
304     return ret;
305 }
306
307 UINT WINAPI MsiRecordGetStringA(MSIHANDLE handle, unsigned int iField, 
308                LPSTR szValue, DWORD *pcchValue)
309 {
310     MSIRECORD *rec;
311     UINT ret;
312
313     TRACE("%ld %d %p %p\n", handle, iField, szValue, pcchValue);
314
315     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
316     if( !rec )
317         return ERROR_INVALID_HANDLE;
318     ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue);
319     msiobj_release( &rec->hdr );
320     return ret;
321 }
322
323 const WCHAR *MSI_RecordGetString( MSIRECORD *rec, unsigned int iField )
324 {
325     if( iField > rec->count )
326         return NULL;
327
328     if( rec->fields[iField].type != MSIFIELD_WSTR )
329         return NULL;
330
331     return rec->fields[iField].u.szwVal;
332 }
333
334 UINT MSI_RecordGetStringW(MSIRECORD *rec, unsigned int iField,
335                LPWSTR szValue, DWORD *pcchValue)
336 {
337     UINT len=0, ret;
338     WCHAR buffer[16];
339     static const WCHAR szFormat[] = { '%','d',0 };
340
341     TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
342
343     if( iField > rec->count )
344         return ERROR_INVALID_PARAMETER;
345
346     ret = ERROR_SUCCESS;
347     switch( rec->fields[iField].type )
348     {
349     case MSIFIELD_INT:
350         wsprintfW(buffer, szFormat, rec->fields[iField].u.iVal);
351         len = lstrlenW( buffer );
352         lstrcpynW(szValue, buffer, *pcchValue);
353         break;
354     case MSIFIELD_WSTR:
355         len = lstrlenW( rec->fields[iField].u.szwVal );
356         lstrcpynW(szValue, rec->fields[iField].u.szwVal, *pcchValue);
357         break;
358     case MSIFIELD_NULL:
359         len = 1;
360         if( *pcchValue > 0 )
361             szValue[0] = 0;
362     default:
363         break;
364     }
365
366     if( *pcchValue < len )
367         ret = ERROR_MORE_DATA;
368     *pcchValue = len;
369
370     return ret;
371 }
372
373 UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, unsigned int iField,
374                LPWSTR szValue, DWORD *pcchValue)
375 {
376     MSIRECORD *rec;
377     UINT ret;
378
379     TRACE("%ld %d %p %p\n", handle, iField, szValue, pcchValue);
380
381     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
382     if( !rec )
383         return ERROR_INVALID_HANDLE;
384
385     ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue );
386     msiobj_release( &rec->hdr );
387     return ret;
388 }
389
390 UINT WINAPI MsiRecordDataSize(MSIHANDLE hRecord, unsigned int iField)
391 {
392     FIXME("%ld %d\n", hRecord, iField);
393     return 0;
394 }
395
396 UINT MSI_RecordSetStringA( MSIRECORD *rec, unsigned int iField, LPCSTR szValue )
397 {
398     LPWSTR str;
399     UINT len;
400
401     TRACE("%p %d %s\n", rec, iField, debugstr_a(szValue));
402
403     if( iField > rec->count )
404         return ERROR_INVALID_FIELD;
405
406     len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 );
407     str = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
408     MultiByteToWideChar( CP_ACP, 0, szValue, -1, str, len );
409     MSI_FreeField( &rec->fields[iField] );
410     rec->fields[iField].type = MSIFIELD_WSTR;
411     rec->fields[iField].u.szwVal = str;
412
413     return 0;
414 }
415
416 UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, unsigned int iField, LPCSTR szValue )
417 {
418     MSIRECORD *rec;
419     UINT ret;
420
421     TRACE("%ld %d %s\n", handle, iField, debugstr_a(szValue));
422
423     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
424     if( !rec )
425         return ERROR_INVALID_HANDLE;
426     ret = MSI_RecordSetStringA( rec, iField, szValue );
427     msiobj_release( &rec->hdr );
428     return ret;
429 }
430
431 UINT MSI_RecordSetStringW( MSIRECORD *rec, unsigned int iField, LPCWSTR szValue )
432 {
433     LPWSTR str;
434     UINT len;
435
436     TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue));
437
438     if( iField > rec->count )
439         return ERROR_INVALID_FIELD;
440
441     len = lstrlenW(szValue) + 1;
442     str = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR));
443     lstrcpyW( str, szValue );
444
445     MSI_FreeField( &rec->fields[iField] );
446     rec->fields[iField].type = MSIFIELD_WSTR;
447     rec->fields[iField].u.szwVal = str;
448
449     return 0;
450 }
451
452 UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, unsigned int iField, LPCWSTR szValue )
453 {
454     MSIRECORD *rec;
455     UINT ret;
456
457     TRACE("%ld %d %s\n", handle, iField, debugstr_w(szValue));
458
459     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
460     if( !rec )
461         return ERROR_INVALID_HANDLE;
462
463     ret = MSI_RecordSetStringW( rec, iField, szValue );
464     msiobj_release( &rec->hdr );
465     return ret;
466 }
467
468 UINT WINAPI MsiFormatRecordA(MSIHANDLE hInstall, MSIHANDLE hRecord, LPSTR szResult, DWORD *sz)
469 {
470     FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
471     return ERROR_CALL_NOT_IMPLEMENTED;
472 }
473
474 UINT WINAPI MsiFormatRecordW(MSIHANDLE hInstall, MSIHANDLE hRecord, LPWSTR szResult, DWORD *sz)
475 {
476     FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
477     return ERROR_CALL_NOT_IMPLEMENTED;
478 }
479
480 UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, unsigned int iField, LPCSTR szFilename)
481 {
482     FIXME("%ld %d %s\n", hRecord, iField, debugstr_a(szFilename));
483     return ERROR_CALL_NOT_IMPLEMENTED;
484 }
485
486 UINT WINAPI MsiRecordSetStreamW(MSIHANDLE hRecord, unsigned int iField, LPCWSTR szFilename)
487 {
488     FIXME("%ld %d %s\n", hRecord, iField, debugstr_w(szFilename));
489     return ERROR_CALL_NOT_IMPLEMENTED;
490 }
491
492 UINT MSI_RecordReadStream(MSIRECORD *rec, unsigned int iField, char *buf, DWORD *sz)
493 {
494     ULONG count;
495     HRESULT r;
496     IStream *stm;
497
498     TRACE("%p %d %p %p\n", rec, iField, buf, sz);
499
500     if( iField > rec->count )
501         return ERROR_INVALID_FIELD;
502
503     if( rec->fields[iField].type != MSIFIELD_STREAM )
504     {
505         *sz = 0;
506         return ERROR_INVALID_FIELD;
507     }
508
509     stm = rec->fields[iField].u.stream;
510     if( !stm )
511         return ERROR_INVALID_FIELD;
512
513     /* if there's no buffer pointer, calculate the length to the end */
514     if( !buf )
515     {
516         LARGE_INTEGER ofs;
517         ULARGE_INTEGER end, cur;
518
519         ofs.QuadPart = cur.QuadPart = 0;
520         end.QuadPart = 0;
521         r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
522         IStream_Seek( stm, ofs, STREAM_SEEK_END, &end );
523         ofs.QuadPart = cur.QuadPart;
524         IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
525         *sz = end.QuadPart - cur.QuadPart;
526
527         return ERROR_SUCCESS;
528     }
529
530     /* read the data */
531     count = 0;
532     r = IStream_Read( stm, buf, *sz, &count );
533     if( FAILED( r ) )
534         return ERROR_FUNCTION_FAILED;
535
536     *sz = count;
537
538     return ERROR_SUCCESS;
539 }
540
541 UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, unsigned int iField, char *buf, DWORD *sz)
542 {
543     MSIRECORD *rec;
544     UINT ret;
545
546     TRACE("%ld %d %p %p\n", handle, iField, buf, sz);
547
548     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
549     if( !rec )
550         return ERROR_INVALID_HANDLE;
551     ret = MSI_RecordReadStream( rec, iField, buf, sz );
552     msiobj_release( &rec->hdr );
553     return ret;
554 }
555
556 UINT MSI_RecordSetIStream( MSIRECORD *rec, unsigned int iField, IStream *stm )
557 {
558     TRACE("%p %d %p\n", rec, iField, stm);
559
560     if( iField > rec->count )
561         return ERROR_INVALID_FIELD;
562
563     MSI_FreeField( &rec->fields[iField] );
564
565     rec->fields[iField].type = MSIFIELD_STREAM;
566     rec->fields[iField].u.stream = stm;
567     IStream_AddRef( stm );
568
569     return ERROR_SUCCESS;
570 }