xref: /reactos/dll/win32/msi/record.c (revision f4be6dc3)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * Implementation of the Microsoft Installer (msi.dll)
3c2c66affSColin Finck  *
4c2c66affSColin Finck  * Copyright 2002-2004 Mike McCormack for CodeWeavers
5c2c66affSColin Finck  *
6c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
7c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
8c2c66affSColin Finck  * License as published by the Free Software Foundation; either
9c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
10c2c66affSColin Finck  *
11c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
12c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14c2c66affSColin Finck  * Lesser General Public License for more details.
15c2c66affSColin Finck  *
16c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
17c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
18c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19c2c66affSColin Finck  */
20c2c66affSColin Finck 
21c42b133eSAmine Khaldi #include <stdarg.h>
22c42b133eSAmine Khaldi 
23c42b133eSAmine Khaldi #define COBJMACROS
24c42b133eSAmine Khaldi 
25c42b133eSAmine Khaldi #include "windef.h"
26c42b133eSAmine Khaldi #include "winbase.h"
27c42b133eSAmine Khaldi #include "winuser.h"
28c42b133eSAmine Khaldi #include "winerror.h"
29c42b133eSAmine Khaldi #include "wine/debug.h"
30c42b133eSAmine Khaldi #include "msi.h"
31c42b133eSAmine Khaldi #include "msiquery.h"
32c2c66affSColin Finck #include "msipriv.h"
33c42b133eSAmine Khaldi #include "objidl.h"
34c42b133eSAmine Khaldi #include "winnls.h"
35c42b133eSAmine Khaldi #include "ole2.h"
36c42b133eSAmine Khaldi 
37c42b133eSAmine Khaldi #include "winreg.h"
38c42b133eSAmine Khaldi #include "shlwapi.h"
39c42b133eSAmine Khaldi 
40c42b133eSAmine Khaldi #include "query.h"
41c2c66affSColin Finck 
42c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(msidb);
43c2c66affSColin Finck 
44c2c66affSColin Finck #define MSIFIELD_NULL   0
45c2c66affSColin Finck #define MSIFIELD_INT    1
46c2c66affSColin Finck #define MSIFIELD_WSTR   3
47c2c66affSColin Finck #define MSIFIELD_STREAM 4
48c2c66affSColin Finck 
MSI_FreeField(MSIFIELD * field)49c2c66affSColin Finck static void MSI_FreeField( MSIFIELD *field )
50c2c66affSColin Finck {
51c2c66affSColin Finck     switch( field->type )
52c2c66affSColin Finck     {
53c2c66affSColin Finck     case MSIFIELD_NULL:
54c2c66affSColin Finck     case MSIFIELD_INT:
55c2c66affSColin Finck         break;
56c2c66affSColin Finck     case MSIFIELD_WSTR:
57*f4be6dc3SMikhail         free( field->u.szwVal);
58c2c66affSColin Finck         break;
59c2c66affSColin Finck     case MSIFIELD_STREAM:
60c2c66affSColin Finck         IStream_Release( field->u.stream );
61c2c66affSColin Finck         break;
62c2c66affSColin Finck     default:
63c2c66affSColin Finck         ERR("Invalid field type %d\n", field->type);
64c2c66affSColin Finck     }
65c2c66affSColin Finck }
66c2c66affSColin Finck 
MSI_CloseRecord(MSIOBJECTHDR * arg)67c2c66affSColin Finck void MSI_CloseRecord( MSIOBJECTHDR *arg )
68c2c66affSColin Finck {
69c2c66affSColin Finck     MSIRECORD *rec = (MSIRECORD *) arg;
70c2c66affSColin Finck     UINT i;
71c2c66affSColin Finck 
72c2c66affSColin Finck     for( i=0; i<=rec->count; i++ )
73c2c66affSColin Finck         MSI_FreeField( &rec->fields[i] );
74c2c66affSColin Finck }
75c2c66affSColin Finck 
MSI_CreateRecord(UINT cParams)76c2c66affSColin Finck MSIRECORD *MSI_CreateRecord( UINT cParams )
77c2c66affSColin Finck {
78c2c66affSColin Finck     MSIRECORD *rec;
79c2c66affSColin Finck 
80c2c66affSColin Finck     TRACE("%d\n", cParams);
81c2c66affSColin Finck 
82c2c66affSColin Finck     if( cParams>65535 )
83c2c66affSColin Finck         return NULL;
84c2c66affSColin Finck 
85c2c66affSColin Finck     rec = alloc_msiobject( MSIHANDLETYPE_RECORD, FIELD_OFFSET(MSIRECORD, fields[cParams + 1]),
86c2c66affSColin Finck             MSI_CloseRecord );
87c2c66affSColin Finck     if( rec )
88c2c66affSColin Finck         rec->count = cParams;
89c2c66affSColin Finck     return rec;
90c2c66affSColin Finck }
91c2c66affSColin Finck 
MsiCreateRecord(UINT cParams)92c2c66affSColin Finck MSIHANDLE WINAPI MsiCreateRecord( UINT cParams )
93c2c66affSColin Finck {
94c2c66affSColin Finck     MSIRECORD *rec;
95c2c66affSColin Finck     MSIHANDLE ret = 0;
96c2c66affSColin Finck 
97c2c66affSColin Finck     TRACE("%d\n", cParams);
98c2c66affSColin Finck 
99c2c66affSColin Finck     rec = MSI_CreateRecord( cParams );
100c2c66affSColin Finck     if( rec )
101c2c66affSColin Finck     {
102c2c66affSColin Finck         ret = alloc_msihandle( &rec->hdr );
103c2c66affSColin Finck         msiobj_release( &rec->hdr );
104c2c66affSColin Finck     }
105c2c66affSColin Finck     return ret;
106c2c66affSColin Finck }
107c2c66affSColin Finck 
MSI_RecordGetFieldCount(const MSIRECORD * rec)108c2c66affSColin Finck UINT MSI_RecordGetFieldCount( const MSIRECORD *rec )
109c2c66affSColin Finck {
110c2c66affSColin Finck     return rec->count;
111c2c66affSColin Finck }
112c2c66affSColin Finck 
MsiRecordGetFieldCount(MSIHANDLE handle)113c2c66affSColin Finck UINT WINAPI MsiRecordGetFieldCount( MSIHANDLE handle )
114c2c66affSColin Finck {
115c2c66affSColin Finck     MSIRECORD *rec;
116c2c66affSColin Finck     UINT ret;
117c2c66affSColin Finck 
11802f995b2Swinesync     TRACE( "%lu\n", handle );
119c2c66affSColin Finck 
120c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
121c2c66affSColin Finck     if( !rec )
122c2c66affSColin Finck         return -1;
123c2c66affSColin Finck 
124c2c66affSColin Finck     msiobj_lock( &rec->hdr );
125c2c66affSColin Finck     ret = MSI_RecordGetFieldCount( rec );
126c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
127c2c66affSColin Finck     msiobj_release( &rec->hdr );
128c2c66affSColin Finck 
129c2c66affSColin Finck     return ret;
130c2c66affSColin Finck }
131c2c66affSColin Finck 
string2intW(LPCWSTR str,int * out)132c2c66affSColin Finck static BOOL string2intW( LPCWSTR str, int *out )
133c2c66affSColin Finck {
134c2c66affSColin Finck     int x = 0;
135c2c66affSColin Finck     LPCWSTR p = str;
136c2c66affSColin Finck 
137c2c66affSColin Finck     if( *p == '-' ) /* skip the minus sign */
138c2c66affSColin Finck         p++;
139c2c66affSColin Finck     while ( *p )
140c2c66affSColin Finck     {
141c2c66affSColin Finck         if( (*p < '0') || (*p > '9') )
142c2c66affSColin Finck             return FALSE;
143c2c66affSColin Finck         x *= 10;
144c2c66affSColin Finck         x += (*p - '0');
145c2c66affSColin Finck         p++;
146c2c66affSColin Finck     }
147c2c66affSColin Finck 
148c2c66affSColin Finck     if( str[0] == '-' ) /* check if it's negative */
149c2c66affSColin Finck         x = -x;
150c2c66affSColin Finck     *out = x;
151c2c66affSColin Finck 
152c2c66affSColin Finck     return TRUE;
153c2c66affSColin Finck }
154c2c66affSColin Finck 
msi_strdupW(const WCHAR * value,int len)155c2c66affSColin Finck WCHAR *msi_strdupW( const WCHAR *value, int len )
156c2c66affSColin Finck {
157c2c66affSColin Finck     WCHAR *ret;
158c2c66affSColin Finck 
159c2c66affSColin Finck     if (!value) return NULL;
160*f4be6dc3SMikhail     if (!(ret = malloc( (len + 1) * sizeof(WCHAR) ))) return NULL;
161c2c66affSColin Finck     memcpy( ret, value, len * sizeof(WCHAR) );
162c2c66affSColin Finck     ret[len] = 0;
163c2c66affSColin Finck     return ret;
164c2c66affSColin Finck }
165c2c66affSColin Finck 
MSI_RecordCopyField(MSIRECORD * in_rec,UINT in_n,MSIRECORD * out_rec,UINT out_n)166c2c66affSColin Finck UINT MSI_RecordCopyField( MSIRECORD *in_rec, UINT in_n,
167c2c66affSColin Finck                           MSIRECORD *out_rec, UINT out_n )
168c2c66affSColin Finck {
169c2c66affSColin Finck     UINT r = ERROR_SUCCESS;
170c2c66affSColin Finck 
171c2c66affSColin Finck     msiobj_lock( &in_rec->hdr );
172c2c66affSColin Finck 
173c2c66affSColin Finck     if ( in_n > in_rec->count || out_n > out_rec->count )
174c2c66affSColin Finck         r = ERROR_FUNCTION_FAILED;
175c2c66affSColin Finck     else if ( in_rec != out_rec || in_n != out_n )
176c2c66affSColin Finck     {
177c2c66affSColin Finck         LPWSTR str;
178c2c66affSColin Finck         MSIFIELD *in, *out;
179c2c66affSColin Finck 
180c2c66affSColin Finck         in = &in_rec->fields[in_n];
181c2c66affSColin Finck         out = &out_rec->fields[out_n];
182c2c66affSColin Finck 
183c2c66affSColin Finck         switch ( in->type )
184c2c66affSColin Finck         {
185c2c66affSColin Finck         case MSIFIELD_NULL:
186c2c66affSColin Finck             break;
187c2c66affSColin Finck         case MSIFIELD_INT:
188c2c66affSColin Finck             out->u.iVal = in->u.iVal;
189c2c66affSColin Finck             break;
190c2c66affSColin Finck         case MSIFIELD_WSTR:
191c2c66affSColin Finck             if ((str = msi_strdupW( in->u.szwVal, in->len )))
192c2c66affSColin Finck             {
193c2c66affSColin Finck                 out->u.szwVal = str;
194c2c66affSColin Finck                 out->len = in->len;
195c2c66affSColin Finck             }
196c2c66affSColin Finck             else r = ERROR_OUTOFMEMORY;
197c2c66affSColin Finck             break;
198c2c66affSColin Finck         case MSIFIELD_STREAM:
199c2c66affSColin Finck             IStream_AddRef( in->u.stream );
200c2c66affSColin Finck             out->u.stream = in->u.stream;
201c2c66affSColin Finck             break;
202c2c66affSColin Finck         default:
203c2c66affSColin Finck             ERR("invalid field type %d\n", in->type);
204c2c66affSColin Finck         }
205c2c66affSColin Finck         if (r == ERROR_SUCCESS)
206c2c66affSColin Finck             out->type = in->type;
207c2c66affSColin Finck     }
208c2c66affSColin Finck 
209c2c66affSColin Finck     msiobj_unlock( &in_rec->hdr );
210c2c66affSColin Finck     return r;
211c2c66affSColin Finck }
212c2c66affSColin Finck 
MSI_RecordGetInteger(MSIRECORD * rec,UINT iField)213c2c66affSColin Finck int MSI_RecordGetInteger( MSIRECORD *rec, UINT iField)
214c2c66affSColin Finck {
215c2c66affSColin Finck     int ret = 0;
216c2c66affSColin Finck 
217c2c66affSColin Finck     TRACE("%p %d\n", rec, iField );
218c2c66affSColin Finck 
219c2c66affSColin Finck     if( iField > rec->count )
220c2c66affSColin Finck         return MSI_NULL_INTEGER;
221c2c66affSColin Finck 
222c2c66affSColin Finck     switch( rec->fields[iField].type )
223c2c66affSColin Finck     {
224c2c66affSColin Finck     case MSIFIELD_INT:
225c2c66affSColin Finck         return rec->fields[iField].u.iVal;
226c2c66affSColin Finck     case MSIFIELD_WSTR:
227c2c66affSColin Finck         if( string2intW( rec->fields[iField].u.szwVal, &ret ) )
228c2c66affSColin Finck             return ret;
229c2c66affSColin Finck         return MSI_NULL_INTEGER;
230c2c66affSColin Finck     default:
231c2c66affSColin Finck         break;
232c2c66affSColin Finck     }
233c2c66affSColin Finck 
234c2c66affSColin Finck     return MSI_NULL_INTEGER;
235c2c66affSColin Finck }
236c2c66affSColin Finck 
MsiRecordGetInteger(MSIHANDLE handle,UINT iField)237c2c66affSColin Finck int WINAPI MsiRecordGetInteger( MSIHANDLE handle, UINT iField)
238c2c66affSColin Finck {
239c2c66affSColin Finck     MSIRECORD *rec;
240c2c66affSColin Finck     UINT ret;
241c2c66affSColin Finck 
24202f995b2Swinesync     TRACE( "%lu, %u\n", handle, iField );
243c2c66affSColin Finck 
244c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
245c2c66affSColin Finck     if( !rec )
246c2c66affSColin Finck         return MSI_NULL_INTEGER;
247c2c66affSColin Finck 
248c2c66affSColin Finck     msiobj_lock( &rec->hdr );
249c2c66affSColin Finck     ret = MSI_RecordGetInteger( rec, iField );
250c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
251c2c66affSColin Finck     msiobj_release( &rec->hdr );
252c2c66affSColin Finck 
253c2c66affSColin Finck     return ret;
254c2c66affSColin Finck }
255c2c66affSColin Finck 
MsiRecordClearData(MSIHANDLE handle)256c2c66affSColin Finck UINT WINAPI MsiRecordClearData( MSIHANDLE handle )
257c2c66affSColin Finck {
258c2c66affSColin Finck     MSIRECORD *rec;
259c2c66affSColin Finck     UINT i;
260c2c66affSColin Finck 
26102f995b2Swinesync     TRACE( "%lu\n", handle );
262c2c66affSColin Finck 
263c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
264c2c66affSColin Finck     if( !rec )
265c2c66affSColin Finck         return ERROR_INVALID_HANDLE;
266c2c66affSColin Finck 
267c2c66affSColin Finck     msiobj_lock( &rec->hdr );
268c2c66affSColin Finck     for( i=0; i<=rec->count; i++)
269c2c66affSColin Finck     {
270c2c66affSColin Finck         MSI_FreeField( &rec->fields[i] );
271c2c66affSColin Finck         rec->fields[i].type = MSIFIELD_NULL;
272c2c66affSColin Finck         rec->fields[i].u.iVal = 0;
273c2c66affSColin Finck     }
274c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
275c2c66affSColin Finck     msiobj_release( &rec->hdr );
276c2c66affSColin Finck 
277c2c66affSColin Finck     return ERROR_SUCCESS;
278c2c66affSColin Finck }
279c2c66affSColin Finck 
MSI_RecordSetInteger(MSIRECORD * rec,UINT iField,int iVal)280c2c66affSColin Finck UINT MSI_RecordSetInteger( MSIRECORD *rec, UINT iField, int iVal )
281c2c66affSColin Finck {
282c2c66affSColin Finck     TRACE("%p %u %d\n", rec, iField, iVal);
283c2c66affSColin Finck 
284c2c66affSColin Finck     if( iField > rec->count )
285c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
286c2c66affSColin Finck 
287c2c66affSColin Finck     MSI_FreeField( &rec->fields[iField] );
28871bffdcdSAmine Khaldi 
28971bffdcdSAmine Khaldi     if (iVal == MSI_NULL_INTEGER)
29071bffdcdSAmine Khaldi     {
29171bffdcdSAmine Khaldi         rec->fields[iField].type = MSIFIELD_NULL;
29271bffdcdSAmine Khaldi         rec->fields[iField].u.szwVal = NULL;
29371bffdcdSAmine Khaldi     }
29471bffdcdSAmine Khaldi     else
29571bffdcdSAmine Khaldi     {
296c2c66affSColin Finck         rec->fields[iField].type = MSIFIELD_INT;
297c2c66affSColin Finck         rec->fields[iField].u.iVal = iVal;
29871bffdcdSAmine Khaldi     }
299c2c66affSColin Finck 
300c2c66affSColin Finck     return ERROR_SUCCESS;
301c2c66affSColin Finck }
302c2c66affSColin Finck 
MsiRecordSetInteger(MSIHANDLE handle,UINT iField,int iVal)303c2c66affSColin Finck UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, UINT iField, int iVal )
304c2c66affSColin Finck {
305c2c66affSColin Finck     MSIRECORD *rec;
306c2c66affSColin Finck     UINT ret;
307c2c66affSColin Finck 
30802f995b2Swinesync     TRACE( "%lu, %u, %d\n", handle, iField, iVal );
309c2c66affSColin Finck 
310c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
311c2c66affSColin Finck     if( !rec )
312c2c66affSColin Finck         return ERROR_INVALID_HANDLE;
313c2c66affSColin Finck 
314c2c66affSColin Finck     msiobj_lock( &rec->hdr );
315c2c66affSColin Finck     ret = MSI_RecordSetInteger( rec, iField, iVal );
316c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
317c2c66affSColin Finck     msiobj_release( &rec->hdr );
318c2c66affSColin Finck     return ret;
319c2c66affSColin Finck }
320c2c66affSColin Finck 
MSI_RecordIsNull(MSIRECORD * rec,UINT iField)321c2c66affSColin Finck BOOL MSI_RecordIsNull( MSIRECORD *rec, UINT iField )
322c2c66affSColin Finck {
323c2c66affSColin Finck     BOOL r = TRUE;
324c2c66affSColin Finck 
325c2c66affSColin Finck     TRACE("%p %d\n", rec, iField );
326c2c66affSColin Finck 
327c2c66affSColin Finck     r = ( iField > rec->count ) ||
328c2c66affSColin Finck         ( rec->fields[iField].type == MSIFIELD_NULL );
329c2c66affSColin Finck 
330c2c66affSColin Finck     return r;
331c2c66affSColin Finck }
332c2c66affSColin Finck 
MsiRecordIsNull(MSIHANDLE handle,UINT iField)333c2c66affSColin Finck BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, UINT iField )
334c2c66affSColin Finck {
335c2c66affSColin Finck     MSIRECORD *rec;
336c2c66affSColin Finck     UINT ret;
337c2c66affSColin Finck 
33802f995b2Swinesync     TRACE( "%lu, %u\n", handle, iField );
339c2c66affSColin Finck 
340c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
341c2c66affSColin Finck     if( !rec )
342c2c66affSColin Finck         return FALSE;
343c2c66affSColin Finck     msiobj_lock( &rec->hdr );
344c2c66affSColin Finck     ret = MSI_RecordIsNull( rec, iField );
345c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
346c2c66affSColin Finck     msiobj_release( &rec->hdr );
347c2c66affSColin Finck     return ret;
348c2c66affSColin Finck 
349c2c66affSColin Finck }
350c2c66affSColin Finck 
MSI_RecordGetStringA(MSIRECORD * rec,UINT iField,LPSTR szValue,LPDWORD pcchValue)351c2c66affSColin Finck UINT MSI_RecordGetStringA(MSIRECORD *rec, UINT iField,
352c2c66affSColin Finck                LPSTR szValue, LPDWORD pcchValue)
353c2c66affSColin Finck {
354c2c66affSColin Finck     UINT len = 0, ret = ERROR_SUCCESS;
355c2c66affSColin Finck     CHAR buffer[16];
356c2c66affSColin Finck 
357c2c66affSColin Finck     TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
358c2c66affSColin Finck 
359c2c66affSColin Finck     if( iField > rec->count )
360c2c66affSColin Finck     {
361c2c66affSColin Finck         if ( szValue && *pcchValue > 0 )
362c2c66affSColin Finck             szValue[0] = 0;
363c2c66affSColin Finck 
364c2c66affSColin Finck         *pcchValue = 0;
365c2c66affSColin Finck         return ERROR_SUCCESS;
366c2c66affSColin Finck     }
367c2c66affSColin Finck 
368c2c66affSColin Finck     switch( rec->fields[iField].type )
369c2c66affSColin Finck     {
370c2c66affSColin Finck     case MSIFIELD_INT:
371c2c66affSColin Finck         wsprintfA(buffer, "%d", rec->fields[iField].u.iVal);
372c2c66affSColin Finck         len = lstrlenA( buffer );
373c2c66affSColin Finck         if (szValue)
374c2c66affSColin Finck             lstrcpynA(szValue, buffer, *pcchValue);
375c2c66affSColin Finck         break;
376c2c66affSColin Finck     case MSIFIELD_WSTR:
377c2c66affSColin Finck         len = WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal,
378c2c66affSColin Finck                                    rec->fields[iField].len + 1, NULL, 0 , NULL, NULL );
379c2c66affSColin Finck         if (szValue)
380c2c66affSColin Finck             WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal,
381c2c66affSColin Finck                                  rec->fields[iField].len + 1, szValue, *pcchValue, NULL, NULL );
382c2c66affSColin Finck         if( szValue && *pcchValue && len>*pcchValue )
383c2c66affSColin Finck             szValue[*pcchValue-1] = 0;
384c2c66affSColin Finck         if( len )
385c2c66affSColin Finck             len--;
386c2c66affSColin Finck         break;
387c2c66affSColin Finck     case MSIFIELD_NULL:
388c2c66affSColin Finck         if( szValue && *pcchValue > 0 )
389c2c66affSColin Finck             szValue[0] = 0;
390c2c66affSColin Finck         break;
391c2c66affSColin Finck     default:
392c2c66affSColin Finck         ret = ERROR_INVALID_PARAMETER;
393c2c66affSColin Finck         break;
394c2c66affSColin Finck     }
395c2c66affSColin Finck 
396c2c66affSColin Finck     if( szValue && *pcchValue <= len )
397c2c66affSColin Finck         ret = ERROR_MORE_DATA;
398c2c66affSColin Finck     *pcchValue = len;
399c2c66affSColin Finck 
400c2c66affSColin Finck     return ret;
401c2c66affSColin Finck }
402c2c66affSColin Finck 
MsiRecordGetStringA(MSIHANDLE handle,UINT iField,char * szValue,DWORD * pcchValue)40302f995b2Swinesync UINT WINAPI MsiRecordGetStringA( MSIHANDLE handle, UINT iField, char *szValue, DWORD *pcchValue )
404c2c66affSColin Finck {
405c2c66affSColin Finck     MSIRECORD *rec;
406c2c66affSColin Finck     UINT ret;
407c2c66affSColin Finck 
40802f995b2Swinesync     TRACE( "%lu, %d, %p, %p\n", handle, iField, szValue, pcchValue );
409c2c66affSColin Finck 
410c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
411c2c66affSColin Finck     if( !rec )
412c2c66affSColin Finck         return ERROR_INVALID_HANDLE;
413c2c66affSColin Finck     msiobj_lock( &rec->hdr );
414c2c66affSColin Finck     ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue);
415c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
416c2c66affSColin Finck     msiobj_release( &rec->hdr );
417c2c66affSColin Finck     return ret;
418c2c66affSColin Finck }
419c2c66affSColin Finck 
msi_record_get_string(const MSIRECORD * rec,UINT field,int * len)420c2c66affSColin Finck const WCHAR *msi_record_get_string( const MSIRECORD *rec, UINT field, int *len )
421c2c66affSColin Finck {
422c2c66affSColin Finck     if (field > rec->count)
423c2c66affSColin Finck         return NULL;
424c2c66affSColin Finck 
425c2c66affSColin Finck     if (rec->fields[field].type != MSIFIELD_WSTR)
426c2c66affSColin Finck         return NULL;
427c2c66affSColin Finck 
428c2c66affSColin Finck     if (len) *len = rec->fields[field].len;
429c2c66affSColin Finck 
430c2c66affSColin Finck     return rec->fields[field].u.szwVal;
431c2c66affSColin Finck }
432c2c66affSColin Finck 
MSI_RecordGetString(const MSIRECORD * rec,UINT iField)433c2c66affSColin Finck const WCHAR *MSI_RecordGetString( const MSIRECORD *rec, UINT iField )
434c2c66affSColin Finck {
435c2c66affSColin Finck     return msi_record_get_string( rec, iField, NULL );
436c2c66affSColin Finck }
437c2c66affSColin Finck 
MSI_RecordGetStringW(MSIRECORD * rec,UINT iField,WCHAR * szValue,DWORD * pcchValue)43802f995b2Swinesync UINT MSI_RecordGetStringW( MSIRECORD *rec, UINT iField, WCHAR *szValue, DWORD *pcchValue )
439c2c66affSColin Finck {
440c2c66affSColin Finck     UINT len = 0, ret = ERROR_SUCCESS;
441c2c66affSColin Finck     WCHAR buffer[16];
442c2c66affSColin Finck 
44302f995b2Swinesync     TRACE( "%p, %u, %p, %p\n", rec, iField, szValue, pcchValue );
444c2c66affSColin Finck 
445c2c66affSColin Finck     if( iField > rec->count )
446c2c66affSColin Finck     {
447c2c66affSColin Finck         if ( szValue && *pcchValue > 0 )
448c2c66affSColin Finck             szValue[0] = 0;
449c2c66affSColin Finck 
450c2c66affSColin Finck         *pcchValue = 0;
451c2c66affSColin Finck         return ERROR_SUCCESS;
452c2c66affSColin Finck     }
453c2c66affSColin Finck 
454c2c66affSColin Finck     switch( rec->fields[iField].type )
455c2c66affSColin Finck     {
456c2c66affSColin Finck     case MSIFIELD_INT:
45774f53b4bSwinesync         wsprintfW(buffer, L"%d", rec->fields[iField].u.iVal);
458c2c66affSColin Finck         len = lstrlenW( buffer );
459c2c66affSColin Finck         if (szValue)
460c2c66affSColin Finck             lstrcpynW(szValue, buffer, *pcchValue);
461c2c66affSColin Finck         break;
462c2c66affSColin Finck     case MSIFIELD_WSTR:
463c2c66affSColin Finck         len = rec->fields[iField].len;
464c2c66affSColin Finck         if (szValue)
465c2c66affSColin Finck             memcpy( szValue, rec->fields[iField].u.szwVal, min(len + 1, *pcchValue) * sizeof(WCHAR) );
466c2c66affSColin Finck         break;
467c2c66affSColin Finck     case MSIFIELD_NULL:
468c2c66affSColin Finck         if( szValue && *pcchValue > 0 )
469c2c66affSColin Finck             szValue[0] = 0;
470c2c66affSColin Finck         break;
471c2c66affSColin Finck     default:
472c2c66affSColin Finck         break;
473c2c66affSColin Finck     }
474c2c66affSColin Finck 
475c2c66affSColin Finck     if( szValue && *pcchValue <= len )
476c2c66affSColin Finck         ret = ERROR_MORE_DATA;
477c2c66affSColin Finck     *pcchValue = len;
478c2c66affSColin Finck 
479c2c66affSColin Finck     return ret;
480c2c66affSColin Finck }
481c2c66affSColin Finck 
MsiRecordGetStringW(MSIHANDLE handle,UINT iField,WCHAR * szValue,DWORD * pcchValue)48202f995b2Swinesync UINT WINAPI MsiRecordGetStringW( MSIHANDLE handle, UINT iField, WCHAR *szValue, DWORD *pcchValue )
483c2c66affSColin Finck {
484c2c66affSColin Finck     MSIRECORD *rec;
485c2c66affSColin Finck     UINT ret;
486c2c66affSColin Finck 
48702f995b2Swinesync     TRACE( "%lu, %u, %p, %p\n", handle, iField, szValue, pcchValue );
488c2c66affSColin Finck 
489c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
490c2c66affSColin Finck     if( !rec )
491c2c66affSColin Finck         return ERROR_INVALID_HANDLE;
492c2c66affSColin Finck 
493c2c66affSColin Finck     msiobj_lock( &rec->hdr );
494c2c66affSColin Finck     ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue );
495c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
496c2c66affSColin Finck     msiobj_release( &rec->hdr );
497c2c66affSColin Finck     return ret;
498c2c66affSColin Finck }
499c2c66affSColin Finck 
get_stream_size(IStream * stm)500*f4be6dc3SMikhail static UINT get_stream_size( IStream *stm )
501c2c66affSColin Finck {
502c2c66affSColin Finck     STATSTG stat;
503c2c66affSColin Finck     HRESULT r;
504c2c66affSColin Finck 
505c2c66affSColin Finck     r = IStream_Stat( stm, &stat, STATFLAG_NONAME );
506c2c66affSColin Finck     if( FAILED(r) )
507c2c66affSColin Finck         return 0;
508c2c66affSColin Finck     return stat.cbSize.QuadPart;
509c2c66affSColin Finck }
510c2c66affSColin Finck 
MSI_RecordDataSize(MSIRECORD * rec,UINT iField)511c2c66affSColin Finck static UINT MSI_RecordDataSize(MSIRECORD *rec, UINT iField)
512c2c66affSColin Finck {
513c2c66affSColin Finck     TRACE("%p %d\n", rec, iField);
514c2c66affSColin Finck 
515c2c66affSColin Finck     if( iField > rec->count )
516c2c66affSColin Finck         return 0;
517c2c66affSColin Finck 
518c2c66affSColin Finck     switch( rec->fields[iField].type )
519c2c66affSColin Finck     {
520c2c66affSColin Finck     case MSIFIELD_INT:
521c2c66affSColin Finck         return sizeof (INT);
522c2c66affSColin Finck     case MSIFIELD_WSTR:
523c2c66affSColin Finck         return rec->fields[iField].len;
524c2c66affSColin Finck     case MSIFIELD_NULL:
525c2c66affSColin Finck         break;
526c2c66affSColin Finck     case MSIFIELD_STREAM:
527*f4be6dc3SMikhail         return get_stream_size( rec->fields[iField].u.stream );
528c2c66affSColin Finck     }
529c2c66affSColin Finck     return 0;
530c2c66affSColin Finck }
531c2c66affSColin Finck 
MsiRecordDataSize(MSIHANDLE handle,UINT iField)532c2c66affSColin Finck UINT WINAPI MsiRecordDataSize( MSIHANDLE handle, UINT iField )
533c2c66affSColin Finck {
534c2c66affSColin Finck     MSIRECORD *rec;
535c2c66affSColin Finck     UINT ret;
536c2c66affSColin Finck 
53702f995b2Swinesync     TRACE( "%lu, %u\n", handle, iField );
538c2c66affSColin Finck 
539c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
540c2c66affSColin Finck     if( !rec )
541c2c66affSColin Finck         return 0;
542c2c66affSColin Finck     msiobj_lock( &rec->hdr );
543c2c66affSColin Finck     ret = MSI_RecordDataSize( rec, iField);
544c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
545c2c66affSColin Finck     msiobj_release( &rec->hdr );
546c2c66affSColin Finck     return ret;
547c2c66affSColin Finck }
548c2c66affSColin Finck 
MsiRecordSetStringA(MSIHANDLE handle,UINT iField,const char * szValue)54902f995b2Swinesync UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, UINT iField, const char *szValue )
550c2c66affSColin Finck {
551c2c66affSColin Finck     WCHAR *valueW = NULL;
552c2c66affSColin Finck     MSIRECORD *rec;
553c2c66affSColin Finck     UINT ret;
554c2c66affSColin Finck 
55502f995b2Swinesync     TRACE( "%lu, %u %s\n", handle, iField, debugstr_a(szValue) );
556c2c66affSColin Finck 
557c2c66affSColin Finck     if (szValue && !(valueW = strdupAtoW( szValue ))) return ERROR_OUTOFMEMORY;
558c2c66affSColin Finck 
559c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
560c2c66affSColin Finck     if( !rec )
561c2c66affSColin Finck     {
562*f4be6dc3SMikhail         free( valueW );
563c2c66affSColin Finck         return ERROR_INVALID_HANDLE;
564c2c66affSColin Finck     }
565c2c66affSColin Finck     msiobj_lock( &rec->hdr );
566c2c66affSColin Finck     ret = MSI_RecordSetStringW( rec, iField, valueW );
567c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
568c2c66affSColin Finck     msiobj_release( &rec->hdr );
569*f4be6dc3SMikhail     free( valueW );
570c2c66affSColin Finck     return ret;
571c2c66affSColin Finck }
572c2c66affSColin Finck 
msi_record_set_string(MSIRECORD * rec,UINT field,const WCHAR * value,int len)573c2c66affSColin Finck UINT msi_record_set_string( MSIRECORD *rec, UINT field, const WCHAR *value, int len )
574c2c66affSColin Finck {
575c2c66affSColin Finck     if (field > rec->count)
576c2c66affSColin Finck         return ERROR_INVALID_FIELD;
577c2c66affSColin Finck 
578c2c66affSColin Finck     MSI_FreeField( &rec->fields[field] );
579c2c66affSColin Finck 
580958f1addSwinesync     if (value && len < 0) len = lstrlenW( value );
581c2c66affSColin Finck 
582c2c66affSColin Finck     if (value && len)
583c2c66affSColin Finck     {
584c2c66affSColin Finck         rec->fields[field].type = MSIFIELD_WSTR;
585c2c66affSColin Finck         rec->fields[field].u.szwVal = msi_strdupW( value, len );
586c2c66affSColin Finck         rec->fields[field].len = len;
587c2c66affSColin Finck     }
588c2c66affSColin Finck     else
589c2c66affSColin Finck     {
590c2c66affSColin Finck         rec->fields[field].type = MSIFIELD_NULL;
591c2c66affSColin Finck         rec->fields[field].u.szwVal = NULL;
592c2c66affSColin Finck         rec->fields[field].len = 0;
593c2c66affSColin Finck     }
594c2c66affSColin Finck     return 0;
595c2c66affSColin Finck }
596c2c66affSColin Finck 
MSI_RecordSetStringW(MSIRECORD * rec,UINT iField,LPCWSTR szValue)597c2c66affSColin Finck UINT MSI_RecordSetStringW( MSIRECORD *rec, UINT iField, LPCWSTR szValue )
598c2c66affSColin Finck {
599c2c66affSColin Finck     TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue));
600c2c66affSColin Finck 
601c2c66affSColin Finck     return msi_record_set_string( rec, iField, szValue, -1 );
602c2c66affSColin Finck }
603c2c66affSColin Finck 
MsiRecordSetStringW(MSIHANDLE handle,UINT iField,const WCHAR * szValue)60402f995b2Swinesync UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, UINT iField, const WCHAR *szValue )
605c2c66affSColin Finck {
606c2c66affSColin Finck     MSIRECORD *rec;
607c2c66affSColin Finck     UINT ret;
608c2c66affSColin Finck 
60902f995b2Swinesync     TRACE( "%lu, %u, %s\n", handle, iField, debugstr_w(szValue) );
610c2c66affSColin Finck 
611c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
612c2c66affSColin Finck     if( !rec )
613c2c66affSColin Finck         return ERROR_INVALID_HANDLE;
614c2c66affSColin Finck 
615c2c66affSColin Finck     msiobj_lock( &rec->hdr );
616c2c66affSColin Finck     ret = MSI_RecordSetStringW( rec, iField, szValue );
617c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
618c2c66affSColin Finck     msiobj_release( &rec->hdr );
619c2c66affSColin Finck     return ret;
620c2c66affSColin Finck }
621c2c66affSColin Finck 
622c2c66affSColin Finck /* read the data in a file into an IStream */
RECORD_StreamFromFile(LPCWSTR szFile,IStream ** pstm)623c2c66affSColin Finck static UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
624c2c66affSColin Finck {
625c2c66affSColin Finck     DWORD sz, szHighWord = 0, read;
626c2c66affSColin Finck     HANDLE handle;
627c2c66affSColin Finck     HGLOBAL hGlob = 0;
628c2c66affSColin Finck     HRESULT hr;
629c2c66affSColin Finck     ULARGE_INTEGER ulSize;
630c2c66affSColin Finck 
631c2c66affSColin Finck     TRACE("reading %s\n", debugstr_w(szFile));
632c2c66affSColin Finck 
633c2c66affSColin Finck     /* read the file into memory */
634c2c66affSColin Finck     handle = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
635c2c66affSColin Finck     if( handle == INVALID_HANDLE_VALUE )
636c2c66affSColin Finck         return GetLastError();
637c2c66affSColin Finck     sz = GetFileSize(handle, &szHighWord);
638c2c66affSColin Finck     if( sz != INVALID_FILE_SIZE && szHighWord == 0 )
639c2c66affSColin Finck     {
640c2c66affSColin Finck         hGlob = GlobalAlloc(GMEM_FIXED, sz);
641c2c66affSColin Finck         if( hGlob )
642c2c66affSColin Finck         {
643c2c66affSColin Finck             BOOL r = ReadFile(handle, hGlob, sz, &read, NULL) && read == sz;
644c2c66affSColin Finck             if( !r )
645c2c66affSColin Finck             {
646c2c66affSColin Finck                 GlobalFree(hGlob);
647c2c66affSColin Finck                 hGlob = 0;
648c2c66affSColin Finck             }
649c2c66affSColin Finck         }
650c2c66affSColin Finck     }
651c2c66affSColin Finck     CloseHandle(handle);
652c2c66affSColin Finck     if( !hGlob )
653c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
654c2c66affSColin Finck 
655c2c66affSColin Finck     /* make a stream out of it, and set the correct file size */
656c2c66affSColin Finck     hr = CreateStreamOnHGlobal(hGlob, TRUE, pstm);
657c2c66affSColin Finck     if( FAILED( hr ) )
658c2c66affSColin Finck     {
659c2c66affSColin Finck         GlobalFree(hGlob);
660c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
661c2c66affSColin Finck     }
662c2c66affSColin Finck 
663c2c66affSColin Finck     /* set the correct size - CreateStreamOnHGlobal screws it up */
664c2c66affSColin Finck     ulSize.QuadPart = sz;
665c2c66affSColin Finck     IStream_SetSize(*pstm, ulSize);
666c2c66affSColin Finck 
66702f995b2Swinesync     TRACE( "read %s, %lu bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm );
668c2c66affSColin Finck     return ERROR_SUCCESS;
669c2c66affSColin Finck }
670c2c66affSColin Finck 
MSI_RecordSetStream(MSIRECORD * rec,UINT iField,IStream * stream)671c2c66affSColin Finck UINT MSI_RecordSetStream(MSIRECORD *rec, UINT iField, IStream *stream)
672c2c66affSColin Finck {
673c2c66affSColin Finck     if ( (iField == 0) || (iField > rec->count) )
674c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
675c2c66affSColin Finck 
676c2c66affSColin Finck     MSI_FreeField( &rec->fields[iField] );
677c2c66affSColin Finck     rec->fields[iField].type = MSIFIELD_STREAM;
678c2c66affSColin Finck     rec->fields[iField].u.stream = stream;
679c2c66affSColin Finck 
680c2c66affSColin Finck     return ERROR_SUCCESS;
681c2c66affSColin Finck }
682c2c66affSColin Finck 
MSI_RecordSetStreamFromFileW(MSIRECORD * rec,UINT iField,LPCWSTR szFilename)683c2c66affSColin Finck UINT MSI_RecordSetStreamFromFileW(MSIRECORD *rec, UINT iField, LPCWSTR szFilename)
684c2c66affSColin Finck {
685c2c66affSColin Finck     IStream *stm = NULL;
686c2c66affSColin Finck     HRESULT hr;
687c2c66affSColin Finck     UINT ret;
688c2c66affSColin Finck 
689c2c66affSColin Finck     if( (iField == 0) || (iField > rec->count) )
690c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
691c2c66affSColin Finck 
692c2c66affSColin Finck     /* no filename means we should seek back to the start of the stream */
693c2c66affSColin Finck     if( !szFilename )
694c2c66affSColin Finck     {
695c2c66affSColin Finck         LARGE_INTEGER ofs;
696c2c66affSColin Finck         ULARGE_INTEGER cur;
697c2c66affSColin Finck 
698c2c66affSColin Finck         if( rec->fields[iField].type != MSIFIELD_STREAM )
699c2c66affSColin Finck             return ERROR_INVALID_FIELD;
700c2c66affSColin Finck 
701c2c66affSColin Finck         stm = rec->fields[iField].u.stream;
702c2c66affSColin Finck         if( !stm )
703c2c66affSColin Finck             return ERROR_INVALID_FIELD;
704c2c66affSColin Finck 
705c2c66affSColin Finck         ofs.QuadPart = 0;
706c2c66affSColin Finck         hr = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
707c2c66affSColin Finck         if (FAILED( hr ))
708c2c66affSColin Finck             return ERROR_FUNCTION_FAILED;
709c2c66affSColin Finck     }
710c2c66affSColin Finck     else
711c2c66affSColin Finck     {
712c2c66affSColin Finck         /* read the file into a stream and save the stream in the record */
713c2c66affSColin Finck         ret = RECORD_StreamFromFile(szFilename, &stm);
714c2c66affSColin Finck         if (ret != ERROR_SUCCESS)
715c2c66affSColin Finck             return ret;
716c2c66affSColin Finck 
717c2c66affSColin Finck         /* if all's good, store it in the record */
718c2c66affSColin Finck         MSI_RecordSetStream(rec, iField, stm);
719c2c66affSColin Finck     }
720c2c66affSColin Finck 
721c2c66affSColin Finck     return ERROR_SUCCESS;
722c2c66affSColin Finck }
723c2c66affSColin Finck 
MsiRecordSetStreamA(MSIHANDLE hRecord,UINT iField,const char * szFilename)72402f995b2Swinesync UINT WINAPI MsiRecordSetStreamA( MSIHANDLE hRecord, UINT iField, const char *szFilename )
725c2c66affSColin Finck {
72602f995b2Swinesync     WCHAR *wstr = NULL;
727c2c66affSColin Finck     UINT ret;
728c2c66affSColin Finck 
72902f995b2Swinesync     TRACE( "%lu, %u, %s\n", hRecord, iField, debugstr_a(szFilename) );
730c2c66affSColin Finck 
731c2c66affSColin Finck     if( szFilename )
732c2c66affSColin Finck     {
733c2c66affSColin Finck         wstr = strdupAtoW( szFilename );
734c2c66affSColin Finck         if( !wstr )
735c2c66affSColin Finck              return ERROR_OUTOFMEMORY;
736c2c66affSColin Finck     }
737c2c66affSColin Finck     ret = MsiRecordSetStreamW(hRecord, iField, wstr);
738*f4be6dc3SMikhail     free(wstr);
739c2c66affSColin Finck 
740c2c66affSColin Finck     return ret;
741c2c66affSColin Finck }
742c2c66affSColin Finck 
MsiRecordSetStreamW(MSIHANDLE handle,UINT iField,const WCHAR * szFilename)74302f995b2Swinesync UINT WINAPI MsiRecordSetStreamW( MSIHANDLE handle, UINT iField, const WCHAR *szFilename )
744c2c66affSColin Finck {
745c2c66affSColin Finck     MSIRECORD *rec;
746c2c66affSColin Finck     UINT ret;
747c2c66affSColin Finck 
74802f995b2Swinesync     TRACE( "%lu, %u, %s\n", handle, iField, debugstr_w(szFilename) );
749c2c66affSColin Finck 
750c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
751c2c66affSColin Finck     if( !rec )
752c2c66affSColin Finck         return ERROR_INVALID_HANDLE;
753c2c66affSColin Finck 
754c2c66affSColin Finck     msiobj_lock( &rec->hdr );
755c2c66affSColin Finck     ret = MSI_RecordSetStreamFromFileW( rec, iField, szFilename );
756c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
757c2c66affSColin Finck     msiobj_release( &rec->hdr );
758c2c66affSColin Finck     return ret;
759c2c66affSColin Finck }
760c2c66affSColin Finck 
MSI_RecordReadStream(MSIRECORD * rec,UINT iField,char * buf,LPDWORD sz)761c2c66affSColin Finck UINT MSI_RecordReadStream(MSIRECORD *rec, UINT iField, char *buf, LPDWORD sz)
762c2c66affSColin Finck {
763c2c66affSColin Finck     ULONG count;
764c2c66affSColin Finck     HRESULT r;
765c2c66affSColin Finck     IStream *stm;
766c2c66affSColin Finck 
767c2c66affSColin Finck     TRACE("%p %d %p %p\n", rec, iField, buf, sz);
768c2c66affSColin Finck 
769c2c66affSColin Finck     if( !sz )
770c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
771c2c66affSColin Finck 
772c2c66affSColin Finck     if( iField > rec->count)
773c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
774c2c66affSColin Finck 
775c2c66affSColin Finck     if ( rec->fields[iField].type == MSIFIELD_NULL )
776c2c66affSColin Finck     {
777c2c66affSColin Finck         *sz = 0;
778c2c66affSColin Finck         return ERROR_INVALID_DATA;
779c2c66affSColin Finck     }
780c2c66affSColin Finck 
781c2c66affSColin Finck     if( rec->fields[iField].type != MSIFIELD_STREAM )
782c2c66affSColin Finck         return ERROR_INVALID_DATATYPE;
783c2c66affSColin Finck 
784c2c66affSColin Finck     stm = rec->fields[iField].u.stream;
785c2c66affSColin Finck     if( !stm )
786c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
787c2c66affSColin Finck 
788c2c66affSColin Finck     /* if there's no buffer pointer, calculate the length to the end */
789c2c66affSColin Finck     if( !buf )
790c2c66affSColin Finck     {
791c2c66affSColin Finck         LARGE_INTEGER ofs;
792c2c66affSColin Finck         ULARGE_INTEGER end, cur;
793c2c66affSColin Finck 
794c2c66affSColin Finck         ofs.QuadPart = cur.QuadPart = 0;
795c2c66affSColin Finck         end.QuadPart = 0;
796c2c66affSColin Finck         IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
797c2c66affSColin Finck         IStream_Seek( stm, ofs, STREAM_SEEK_END, &end );
798c2c66affSColin Finck         ofs.QuadPart = cur.QuadPart;
799c2c66affSColin Finck         IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
800c2c66affSColin Finck         *sz = end.QuadPart - cur.QuadPart;
801c2c66affSColin Finck 
802c2c66affSColin Finck         return ERROR_SUCCESS;
803c2c66affSColin Finck     }
804c2c66affSColin Finck 
805c2c66affSColin Finck     /* read the data */
806c2c66affSColin Finck     count = 0;
807c2c66affSColin Finck     r = IStream_Read( stm, buf, *sz, &count );
808c2c66affSColin Finck     if( FAILED( r ) )
809c2c66affSColin Finck     {
810c2c66affSColin Finck         *sz = 0;
811c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
812c2c66affSColin Finck     }
813c2c66affSColin Finck 
814c2c66affSColin Finck     *sz = count;
815c2c66affSColin Finck 
816c2c66affSColin Finck     return ERROR_SUCCESS;
817c2c66affSColin Finck }
818c2c66affSColin Finck 
MsiRecordReadStream(MSIHANDLE handle,UINT iField,char * buf,DWORD * sz)81902f995b2Swinesync UINT WINAPI MsiRecordReadStream( MSIHANDLE handle, UINT iField, char *buf, DWORD *sz )
820c2c66affSColin Finck {
821c2c66affSColin Finck     MSIRECORD *rec;
822c2c66affSColin Finck     UINT ret;
823c2c66affSColin Finck 
82402f995b2Swinesync     TRACE( "%lu, %u, %p, %p\n", handle, iField, buf, sz );
825c2c66affSColin Finck 
826c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
827c2c66affSColin Finck     if( !rec )
828c2c66affSColin Finck         return ERROR_INVALID_HANDLE;
829c2c66affSColin Finck     msiobj_lock( &rec->hdr );
830c2c66affSColin Finck     ret = MSI_RecordReadStream( rec, iField, buf, sz );
831c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
832c2c66affSColin Finck     msiobj_release( &rec->hdr );
833c2c66affSColin Finck     return ret;
834c2c66affSColin Finck }
835c2c66affSColin Finck 
MSI_RecordSetIStream(MSIRECORD * rec,UINT iField,IStream * stm)836c2c66affSColin Finck UINT MSI_RecordSetIStream( MSIRECORD *rec, UINT iField, IStream *stm )
837c2c66affSColin Finck {
838c2c66affSColin Finck     TRACE("%p %d %p\n", rec, iField, stm);
839c2c66affSColin Finck 
840c2c66affSColin Finck     if( iField > rec->count )
841c2c66affSColin Finck         return ERROR_INVALID_FIELD;
842c2c66affSColin Finck 
843c2c66affSColin Finck     MSI_FreeField( &rec->fields[iField] );
844c2c66affSColin Finck 
845c2c66affSColin Finck     rec->fields[iField].type = MSIFIELD_STREAM;
846c2c66affSColin Finck     rec->fields[iField].u.stream = stm;
847c2c66affSColin Finck     IStream_AddRef( stm );
848c2c66affSColin Finck 
849c2c66affSColin Finck     return ERROR_SUCCESS;
850c2c66affSColin Finck }
851c2c66affSColin Finck 
MSI_RecordGetIStream(MSIRECORD * rec,UINT iField,IStream ** pstm)852c2c66affSColin Finck UINT MSI_RecordGetIStream( MSIRECORD *rec, UINT iField, IStream **pstm)
853c2c66affSColin Finck {
854c2c66affSColin Finck     TRACE("%p %d %p\n", rec, iField, pstm);
855c2c66affSColin Finck 
856c2c66affSColin Finck     if( iField > rec->count )
857c2c66affSColin Finck         return ERROR_INVALID_FIELD;
858c2c66affSColin Finck 
859c2c66affSColin Finck     if( rec->fields[iField].type != MSIFIELD_STREAM )
860c2c66affSColin Finck         return ERROR_INVALID_FIELD;
861c2c66affSColin Finck 
862c2c66affSColin Finck     *pstm = rec->fields[iField].u.stream;
863c2c66affSColin Finck     IStream_AddRef( *pstm );
864c2c66affSColin Finck 
865c2c66affSColin Finck     return ERROR_SUCCESS;
866c2c66affSColin Finck }
867c2c66affSColin Finck 
dump_stream_to_file(IStream * stm,const WCHAR * name)868*f4be6dc3SMikhail static UINT dump_stream_to_file( IStream *stm, const WCHAR *name )
869c2c66affSColin Finck {
870c2c66affSColin Finck     ULARGE_INTEGER size;
871c2c66affSColin Finck     LARGE_INTEGER pos;
872c2c66affSColin Finck     IStream *out;
873c2c66affSColin Finck     DWORD stgm;
874c2c66affSColin Finck     HRESULT r;
875c2c66affSColin Finck 
876c2c66affSColin Finck     stgm = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_FAILIFTHERE;
877c2c66affSColin Finck     r = SHCreateStreamOnFileW( name, stgm, &out );
878c2c66affSColin Finck     if( FAILED( r ) )
879c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
880c2c66affSColin Finck 
881c2c66affSColin Finck     pos.QuadPart = 0;
882c2c66affSColin Finck     r = IStream_Seek( stm, pos, STREAM_SEEK_END, &size );
883c2c66affSColin Finck     if( FAILED( r ) )
884c2c66affSColin Finck         goto end;
885c2c66affSColin Finck 
886c2c66affSColin Finck     pos.QuadPart = 0;
887c2c66affSColin Finck     r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL );
888c2c66affSColin Finck     if( FAILED( r ) )
889c2c66affSColin Finck         goto end;
890c2c66affSColin Finck 
891c2c66affSColin Finck     r = IStream_CopyTo( stm, out, size, NULL, NULL );
892c2c66affSColin Finck 
893c2c66affSColin Finck end:
894c2c66affSColin Finck     IStream_Release( out );
895c2c66affSColin Finck     if( FAILED( r ) )
896c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
897c2c66affSColin Finck     return ERROR_SUCCESS;
898c2c66affSColin Finck }
899c2c66affSColin Finck 
MSI_RecordStreamToFile(MSIRECORD * rec,UINT iField,LPCWSTR name)900c2c66affSColin Finck UINT MSI_RecordStreamToFile( MSIRECORD *rec, UINT iField, LPCWSTR name )
901c2c66affSColin Finck {
902c2c66affSColin Finck     IStream *stm = NULL;
903c2c66affSColin Finck     UINT r;
904c2c66affSColin Finck 
905c2c66affSColin Finck     TRACE("%p %u %s\n", rec, iField, debugstr_w(name));
906c2c66affSColin Finck 
907c2c66affSColin Finck     msiobj_lock( &rec->hdr );
908c2c66affSColin Finck 
909c2c66affSColin Finck     r = MSI_RecordGetIStream( rec, iField, &stm );
910c2c66affSColin Finck     if( r == ERROR_SUCCESS )
911c2c66affSColin Finck     {
912*f4be6dc3SMikhail         r = dump_stream_to_file( stm, name );
913c2c66affSColin Finck         IStream_Release( stm );
914c2c66affSColin Finck     }
915c2c66affSColin Finck 
916c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
917c2c66affSColin Finck 
918c2c66affSColin Finck     return r;
919c2c66affSColin Finck }
920c2c66affSColin Finck 
MSI_CloneRecord(MSIRECORD * rec)921c2c66affSColin Finck MSIRECORD *MSI_CloneRecord(MSIRECORD *rec)
922c2c66affSColin Finck {
923c2c66affSColin Finck     MSIRECORD *clone;
924c2c66affSColin Finck     UINT r, i, count;
925c2c66affSColin Finck 
926c2c66affSColin Finck     count = MSI_RecordGetFieldCount(rec);
927c2c66affSColin Finck     clone = MSI_CreateRecord(count);
928c2c66affSColin Finck     if (!clone)
929c2c66affSColin Finck         return NULL;
930c2c66affSColin Finck 
931c2c66affSColin Finck     for (i = 0; i <= count; i++)
932c2c66affSColin Finck     {
933c2c66affSColin Finck         if (rec->fields[i].type == MSIFIELD_STREAM)
934c2c66affSColin Finck         {
935c2c66affSColin Finck             if (FAILED(IStream_Clone(rec->fields[i].u.stream,
936c2c66affSColin Finck                                      &clone->fields[i].u.stream)))
937c2c66affSColin Finck             {
938c2c66affSColin Finck                 msiobj_release(&clone->hdr);
939c2c66affSColin Finck                 return NULL;
940c2c66affSColin Finck             }
941c2c66affSColin Finck             clone->fields[i].type = MSIFIELD_STREAM;
942c2c66affSColin Finck         }
943c2c66affSColin Finck         else
944c2c66affSColin Finck         {
945c2c66affSColin Finck             r = MSI_RecordCopyField(rec, i, clone, i);
946c2c66affSColin Finck             if (r != ERROR_SUCCESS)
947c2c66affSColin Finck             {
948c2c66affSColin Finck                 msiobj_release(&clone->hdr);
949c2c66affSColin Finck                 return NULL;
950c2c66affSColin Finck             }
951c2c66affSColin Finck         }
952c2c66affSColin Finck     }
953c2c66affSColin Finck 
954c2c66affSColin Finck     return clone;
955c2c66affSColin Finck }
956c2c66affSColin Finck 
MSI_RecordsAreFieldsEqual(MSIRECORD * a,MSIRECORD * b,UINT field)957c2c66affSColin Finck BOOL MSI_RecordsAreFieldsEqual(MSIRECORD *a, MSIRECORD *b, UINT field)
958c2c66affSColin Finck {
959c2c66affSColin Finck     if (a->fields[field].type != b->fields[field].type)
960c2c66affSColin Finck         return FALSE;
961c2c66affSColin Finck 
962c2c66affSColin Finck     switch (a->fields[field].type)
963c2c66affSColin Finck     {
964c2c66affSColin Finck         case MSIFIELD_NULL:
965c2c66affSColin Finck             break;
966c2c66affSColin Finck 
967c2c66affSColin Finck         case MSIFIELD_INT:
968c2c66affSColin Finck             if (a->fields[field].u.iVal != b->fields[field].u.iVal)
969c2c66affSColin Finck                 return FALSE;
970c2c66affSColin Finck             break;
971c2c66affSColin Finck 
972c2c66affSColin Finck         case MSIFIELD_WSTR:
973c2c66affSColin Finck             if (a->fields[field].len != b->fields[field].len) return FALSE;
974c2c66affSColin Finck             if (memcmp( a->fields[field].u.szwVal, b->fields[field].u.szwVal,
975c2c66affSColin Finck                         a->fields[field].len * sizeof(WCHAR) )) return FALSE;
976c2c66affSColin Finck             break;
977c2c66affSColin Finck 
978c2c66affSColin Finck         case MSIFIELD_STREAM:
979c2c66affSColin Finck         default:
980c2c66affSColin Finck             return FALSE;
981c2c66affSColin Finck     }
982c2c66affSColin Finck     return TRUE;
983c2c66affSColin Finck }
984c2c66affSColin Finck 
985c2c66affSColin Finck 
MSI_RecordsAreEqual(MSIRECORD * a,MSIRECORD * b)986c2c66affSColin Finck BOOL MSI_RecordsAreEqual(MSIRECORD *a, MSIRECORD *b)
987c2c66affSColin Finck {
988c2c66affSColin Finck     UINT i;
989c2c66affSColin Finck 
990c2c66affSColin Finck     if (a->count != b->count)
991c2c66affSColin Finck         return FALSE;
992c2c66affSColin Finck 
993c2c66affSColin Finck     for (i = 0; i <= a->count; i++)
994c2c66affSColin Finck     {
995c2c66affSColin Finck         if (!MSI_RecordsAreFieldsEqual( a, b, i ))
996c2c66affSColin Finck             return FALSE;
997c2c66affSColin Finck     }
998c2c66affSColin Finck 
999c2c66affSColin Finck     return TRUE;
1000c2c66affSColin Finck }
1001c2c66affSColin Finck 
msi_dup_record_field(MSIRECORD * rec,INT field)1002c2c66affSColin Finck WCHAR *msi_dup_record_field( MSIRECORD *rec, INT field )
1003c2c66affSColin Finck {
1004c2c66affSColin Finck     DWORD sz = 0;
1005c2c66affSColin Finck     WCHAR *str;
1006c2c66affSColin Finck     UINT r;
1007c2c66affSColin Finck 
1008c2c66affSColin Finck     if (MSI_RecordIsNull( rec, field )) return NULL;
1009c2c66affSColin Finck 
1010c2c66affSColin Finck     r = MSI_RecordGetStringW( rec, field, NULL, &sz );
1011c2c66affSColin Finck     if (r != ERROR_SUCCESS)
1012c2c66affSColin Finck         return NULL;
1013c2c66affSColin Finck 
1014c2c66affSColin Finck     sz++;
1015*f4be6dc3SMikhail     str = malloc( sz * sizeof(WCHAR) );
1016c2c66affSColin Finck     if (!str) return NULL;
1017c2c66affSColin Finck     str[0] = 0;
1018c2c66affSColin Finck     r = MSI_RecordGetStringW( rec, field, str, &sz );
1019c2c66affSColin Finck     if (r != ERROR_SUCCESS)
1020c2c66affSColin Finck     {
1021c2c66affSColin Finck         ERR("failed to get string!\n");
1022*f4be6dc3SMikhail         free( str );
1023c2c66affSColin Finck         return NULL;
1024c2c66affSColin Finck     }
1025c2c66affSColin Finck     return str;
1026c2c66affSColin Finck }
102771bffdcdSAmine Khaldi 
dump_record(MSIRECORD * rec)102871bffdcdSAmine Khaldi void dump_record(MSIRECORD *rec)
102971bffdcdSAmine Khaldi {
103071bffdcdSAmine Khaldi     int i;
103171bffdcdSAmine Khaldi     if (!rec)
103271bffdcdSAmine Khaldi     {
103371bffdcdSAmine Khaldi         TRACE("(null)\n");
103471bffdcdSAmine Khaldi         return;
103571bffdcdSAmine Khaldi     }
103671bffdcdSAmine Khaldi 
103771bffdcdSAmine Khaldi     TRACE("[");
103871bffdcdSAmine Khaldi     for (i = 0; i <= rec->count; i++)
103971bffdcdSAmine Khaldi     {
104071bffdcdSAmine Khaldi         switch(rec->fields[i].type)
104171bffdcdSAmine Khaldi         {
104271bffdcdSAmine Khaldi         case MSIFIELD_NULL: TRACE("(null)"); break;
104371bffdcdSAmine Khaldi         case MSIFIELD_INT: TRACE("%d", rec->fields[i].u.iVal); break;
104471bffdcdSAmine Khaldi         case MSIFIELD_WSTR: TRACE("%s", debugstr_w(rec->fields[i].u.szwVal)); break;
104571bffdcdSAmine Khaldi         case MSIFIELD_STREAM: TRACE("%p", rec->fields[i].u.stream); break;
104671bffdcdSAmine Khaldi         }
104771bffdcdSAmine Khaldi         if (i < rec->count) TRACE(", ");
104871bffdcdSAmine Khaldi     }
104971bffdcdSAmine Khaldi     TRACE("]\n");
105071bffdcdSAmine Khaldi }
10512e19edd6Swinesync 
copy_remote_record(const struct wire_record * in,MSIHANDLE out)1052aede536cSwinesync UINT copy_remote_record(const struct wire_record *in, MSIHANDLE out)
10532e19edd6Swinesync {
10542e19edd6Swinesync     MSIRECORD *rec;
10552e19edd6Swinesync     unsigned int i;
10568c04add1Swinesync     UINT r = ERROR_SUCCESS;
10572e19edd6Swinesync 
1058aede536cSwinesync     if (!(rec = msihandle2msiinfo(out, MSIHANDLETYPE_RECORD)))
1059aede536cSwinesync         return ERROR_INVALID_HANDLE;
10602e19edd6Swinesync 
106114478462Swinesync     rec->cookie = in->cookie;
10622e19edd6Swinesync     for (i = 0; i <= in->count; i++)
10632e19edd6Swinesync     {
10642e19edd6Swinesync         switch (in->fields[i].type)
10652e19edd6Swinesync         {
10662e19edd6Swinesync         case MSIFIELD_NULL:
1067aede536cSwinesync             MSI_FreeField(&rec->fields[i]);
1068aede536cSwinesync             rec->fields[i].type = MSIFIELD_NULL;
10692e19edd6Swinesync             break;
10702e19edd6Swinesync         case MSIFIELD_INT:
10712e19edd6Swinesync             r = MSI_RecordSetInteger(rec, i, in->fields[i].u.iVal);
10722e19edd6Swinesync             break;
10732e19edd6Swinesync         case MSIFIELD_WSTR:
10742e19edd6Swinesync             r = MSI_RecordSetStringW(rec, i, in->fields[i].u.szwVal);
10752e19edd6Swinesync             break;
10762e19edd6Swinesync         case MSIFIELD_STREAM:
10772e19edd6Swinesync             r = MSI_RecordSetIStream(rec, i, in->fields[i].u.stream);
10782e19edd6Swinesync             break;
10792e19edd6Swinesync         default:
10802e19edd6Swinesync             ERR("invalid field type %d\n", in->fields[i].type);
10812e19edd6Swinesync             break;
10822e19edd6Swinesync         }
10832e19edd6Swinesync 
10842e19edd6Swinesync         if (r)
10852e19edd6Swinesync         {
10862e19edd6Swinesync             msiobj_release(&rec->hdr);
10872e19edd6Swinesync             return r;
10882e19edd6Swinesync         }
10892e19edd6Swinesync     }
10902e19edd6Swinesync 
10912e19edd6Swinesync     msiobj_release(&rec->hdr);
10922e19edd6Swinesync     return ERROR_SUCCESS;
10932e19edd6Swinesync }
1094795da528Swinesync 
unmarshal_record(const struct wire_record * in,MSIHANDLE * out)1095aede536cSwinesync UINT unmarshal_record(const struct wire_record *in, MSIHANDLE *out)
1096aede536cSwinesync {
1097aede536cSwinesync     if (!in)
1098aede536cSwinesync     {
1099aede536cSwinesync         *out = 0;
1100aede536cSwinesync         return ERROR_SUCCESS;
1101aede536cSwinesync     }
1102aede536cSwinesync 
1103aede536cSwinesync     *out = MsiCreateRecord(in->count);
1104aede536cSwinesync     if (!*out) return ERROR_OUTOFMEMORY;
1105aede536cSwinesync 
1106aede536cSwinesync     return copy_remote_record(in, *out);
1107aede536cSwinesync }
1108aede536cSwinesync 
marshal_record(MSIHANDLE handle)1109795da528Swinesync struct wire_record *marshal_record(MSIHANDLE handle)
1110795da528Swinesync {
1111795da528Swinesync     struct wire_record *ret;
111214478462Swinesync     unsigned int i;
1113795da528Swinesync     MSIRECORD *rec;
1114795da528Swinesync 
1115795da528Swinesync     if (!(rec = msihandle2msiinfo(handle, MSIHANDLETYPE_RECORD)))
1116795da528Swinesync         return NULL;
1117795da528Swinesync 
111814478462Swinesync     ret = midl_user_allocate(sizeof(*ret) + rec->count * sizeof(ret->fields[0]));
111914478462Swinesync     ret->count = rec->count;
112014478462Swinesync     ret->cookie = rec->cookie;
1121795da528Swinesync 
112214478462Swinesync     for (i = 0; i <= rec->count; i++)
1123795da528Swinesync     {
1124795da528Swinesync         switch (rec->fields[i].type)
1125795da528Swinesync         {
1126795da528Swinesync         case MSIFIELD_NULL:
1127795da528Swinesync             break;
1128795da528Swinesync         case MSIFIELD_INT:
1129795da528Swinesync             ret->fields[i].u.iVal = rec->fields[i].u.iVal;
1130795da528Swinesync             break;
1131795da528Swinesync         case MSIFIELD_WSTR:
1132*f4be6dc3SMikhail             ret->fields[i].u.szwVal = wcsdup(rec->fields[i].u.szwVal);
1133795da528Swinesync             break;
1134795da528Swinesync         case MSIFIELD_STREAM:
1135795da528Swinesync             IStream_AddRef(rec->fields[i].u.stream);
1136795da528Swinesync             ret->fields[i].u.stream = rec->fields[i].u.stream;
1137795da528Swinesync             break;
1138795da528Swinesync         default:
1139795da528Swinesync             ERR("invalid field type %d\n", rec->fields[i].type);
1140795da528Swinesync             break;
1141795da528Swinesync         }
1142795da528Swinesync         ret->fields[i].type = rec->fields[i].type;
1143795da528Swinesync     }
1144795da528Swinesync 
1145795da528Swinesync     msiobj_release(&rec->hdr);
1146795da528Swinesync     return ret;
1147795da528Swinesync }
1148795da528Swinesync 
free_remote_record(struct wire_record * rec)1149795da528Swinesync void free_remote_record(struct wire_record *rec)
1150795da528Swinesync {
1151795da528Swinesync     int i;
1152795da528Swinesync 
1153795da528Swinesync     for (i = 0; i <= rec->count; i++)
1154795da528Swinesync     {
1155795da528Swinesync         if (rec->fields[i].type == MSIFIELD_WSTR)
1156795da528Swinesync             midl_user_free(rec->fields[i].u.szwVal);
1157795da528Swinesync         else if (rec->fields[i].type == MSIFIELD_STREAM)
1158795da528Swinesync             IStream_Release(rec->fields[i].u.stream);
1159795da528Swinesync     }
1160795da528Swinesync 
1161795da528Swinesync     midl_user_free(rec);
1162795da528Swinesync }
1163