bcrypt: Add BCryptDeriveKey stub.
[wine.git] / dlls / msi / font.c
blob08dcc149579d778b1031c29f72876f8ef00f103e
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
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.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "winerror.h"
25 #include "winreg.h"
26 #include "wine/debug.h"
27 #include "msipriv.h"
28 #include "wine/unicode.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(msi);
32 typedef struct _tagTT_OFFSET_TABLE {
33 USHORT uMajorVersion;
34 USHORT uMinorVersion;
35 USHORT uNumOfTables;
36 USHORT uSearchRange;
37 USHORT uEntrySelector;
38 USHORT uRangeShift;
39 } TT_OFFSET_TABLE;
41 typedef struct _tagTT_TABLE_DIRECTORY {
42 char szTag[4]; /* table name */
43 ULONG uCheckSum; /* Check sum */
44 ULONG uOffset; /* Offset from beginning of file */
45 ULONG uLength; /* length of the table in bytes */
46 } TT_TABLE_DIRECTORY;
48 typedef struct _tagTT_NAME_TABLE_HEADER {
49 USHORT uFSelector; /* format selector. Always 0 */
50 USHORT uNRCount; /* Name Records count */
51 USHORT uStorageOffset; /* Offset for strings storage,
52 * from start of the table */
53 } TT_NAME_TABLE_HEADER;
55 #define NAME_ID_FULL_FONT_NAME 4
56 #define NAME_ID_VERSION 5
58 typedef struct _tagTT_NAME_RECORD {
59 USHORT uPlatformID;
60 USHORT uEncodingID;
61 USHORT uLanguageID;
62 USHORT uNameID;
63 USHORT uStringLength;
64 USHORT uStringOffset; /* from start of storage area */
65 } TT_NAME_RECORD;
67 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
68 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
70 static const WCHAR regfont1[] =
71 {'S','o','f','t','w','a','r','e','\\',
72 'M','i','c','r','o','s','o','f','t','\\',
73 'W','i','n','d','o','w','s',' ','N','T','\\',
74 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
75 'F','o','n','t','s',0};
76 static const WCHAR regfont2[] =
77 {'S','o','f','t','w','a','r','e','\\',
78 'M','i','c','r','o','s','o','f','t','\\',
79 'W','i','n','d','o','w','s','\\',
80 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
81 'F','o','n','t','s',0};
84 * Code based off of code located here
85 * http://www.codeproject.com/gdi/fontnamefromfile.asp
87 static WCHAR *load_ttf_name_id( MSIPACKAGE *package, const WCHAR *filename, DWORD id )
89 TT_TABLE_DIRECTORY tblDir;
90 BOOL bFound = FALSE;
91 TT_OFFSET_TABLE ttOffsetTable;
92 TT_NAME_TABLE_HEADER ttNTHeader;
93 TT_NAME_RECORD ttRecord;
94 DWORD dwRead;
95 HANDLE handle;
96 LPWSTR ret = NULL;
97 int i;
99 if (package)
100 handle = msi_create_file( package, filename, GENERIC_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL );
101 else
102 handle = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );
103 if (handle == INVALID_HANDLE_VALUE)
105 ERR("Unable to open font file %s\n", debugstr_w(filename));
106 return NULL;
109 if (!ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL))
110 goto end;
112 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
113 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
114 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
116 if ((ttOffsetTable.uMajorVersion != 1 || ttOffsetTable.uMinorVersion != 0) &&
117 (ttOffsetTable.uMajorVersion != 0x4f54 || ttOffsetTable.uMinorVersion != 0x544f))
118 goto end;
120 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
122 if (!ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL))
123 break;
124 if (memcmp(tblDir.szTag,"name",4)==0)
126 bFound = TRUE;
127 tblDir.uLength = SWAPLONG(tblDir.uLength);
128 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
129 break;
133 if (!bFound)
134 goto end;
136 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
137 if (!ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER), &dwRead,NULL))
138 goto end;
140 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
141 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
142 for(i=0; i<ttNTHeader.uNRCount; i++)
144 if (!ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL))
145 break;
147 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
148 ttRecord.uPlatformID = SWAPWORD(ttRecord.uPlatformID);
149 ttRecord.uEncodingID = SWAPWORD(ttRecord.uEncodingID);
150 if (ttRecord.uNameID == id && ttRecord.uPlatformID == 3 &&
151 (ttRecord.uEncodingID == 0 || ttRecord.uEncodingID == 1))
153 WCHAR *buf;
154 unsigned int i;
156 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
157 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
158 SetFilePointer(handle, tblDir.uOffset + ttRecord.uStringOffset + ttNTHeader.uStorageOffset,
159 NULL, FILE_BEGIN);
160 if (!(buf = msi_alloc_zero( ttRecord.uStringLength + sizeof(WCHAR) ))) goto end;
161 dwRead = 0;
162 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
163 if (dwRead % sizeof(WCHAR))
165 msi_free(buf);
166 goto end;
168 for (i = 0; i < dwRead / sizeof(WCHAR); i++) buf[i] = SWAPWORD(buf[i]);
169 ret = strdupW(buf);
170 msi_free(buf);
171 break;
175 end:
176 CloseHandle(handle);
177 return ret;
180 static WCHAR *font_name_from_file( MSIPACKAGE *package, const WCHAR *filename )
182 static const WCHAR truetypeW[] = {' ','(','T','r','u','e','T','y','p','e',')',0};
183 WCHAR *name, *ret = NULL;
185 if ((name = load_ttf_name_id( package, filename, NAME_ID_FULL_FONT_NAME )))
187 if (!name[0])
189 WARN("empty font name\n");
190 msi_free( name );
191 return NULL;
193 ret = msi_alloc( (strlenW( name ) + strlenW( truetypeW ) + 1 ) * sizeof(WCHAR) );
194 strcpyW( ret, name );
195 strcatW( ret, truetypeW );
196 msi_free( name );
198 return ret;
201 WCHAR *msi_get_font_file_version( MSIPACKAGE *package, const WCHAR *filename )
203 static const WCHAR fmtW[] = {'%','u','.','%','u','.','0','.','0',0};
204 WCHAR *version, *p, *q, *ret = NULL;
206 if ((version = load_ttf_name_id( package, filename, NAME_ID_VERSION )))
208 int len, major = 0, minor = 0;
209 if ((p = strchrW( version, ';' ))) *p = 0;
210 p = version;
211 while (*p && !isdigitW( *p )) p++;
212 if ((q = strchrW( p, '.' )))
214 major = atoiW( p );
215 p = ++q;
216 while (*q && isdigitW( *q )) q++;
217 if (!*q || *q == ' ') minor = atoiW( p );
218 else major = 0;
220 len = strlenW( fmtW ) + 20;
221 ret = msi_alloc( len * sizeof(WCHAR) );
222 sprintfW( ret, fmtW, major, minor );
223 msi_free( version );
225 return ret;
228 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
230 MSIPACKAGE *package = param;
231 LPWSTR name;
232 LPCWSTR filename;
233 MSIFILE *file;
234 MSICOMPONENT *comp;
235 HKEY hkey1, hkey2;
236 MSIRECORD *uirow;
237 LPWSTR uipath, p;
239 filename = MSI_RecordGetString( row, 1 );
240 file = msi_get_loaded_file( package, filename );
241 if (!file)
243 WARN("unable to find file %s\n", debugstr_w(filename));
244 return ERROR_SUCCESS;
246 comp = msi_get_loaded_component( package, file->Component->Component );
247 if (!comp)
249 WARN("unable to find component %s\n", debugstr_w(file->Component->Component));
250 return ERROR_SUCCESS;
252 comp->Action = msi_get_component_action( package, comp );
253 if (comp->Action != INSTALLSTATE_LOCAL)
255 TRACE("component not scheduled for installation %s\n", debugstr_w(comp->Component));
256 return ERROR_SUCCESS;
259 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
260 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
262 if (MSI_RecordIsNull(row,2))
263 name = font_name_from_file( package, file->TargetPath );
264 else
265 name = msi_dup_record_field(row,2);
267 if (name)
269 msi_reg_set_val_str( hkey1, name, file->TargetPath);
270 msi_reg_set_val_str( hkey2, name, file->TargetPath);
273 msi_free(name);
274 RegCloseKey(hkey1);
275 RegCloseKey(hkey2);
277 /* the UI chunk */
278 uirow = MSI_CreateRecord( 1 );
279 uipath = strdupW( file->TargetPath );
280 p = strrchrW(uipath,'\\');
281 if (p) p++;
282 else p = uipath;
283 MSI_RecordSetStringW( uirow, 1, p );
284 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
285 msiobj_release( &uirow->hdr );
286 msi_free( uipath );
287 /* FIXME: call msi_ui_progress? */
289 return ERROR_SUCCESS;
292 UINT ACTION_RegisterFonts(MSIPACKAGE *package)
294 static const WCHAR query[] = {
295 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','F','o','n','t','`',0};
296 MSIQUERY *view;
297 UINT rc;
299 if (package->script == SCRIPT_NONE)
300 return msi_schedule_action(package, SCRIPT_INSTALL, szRegisterFonts);
302 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
303 if (rc != ERROR_SUCCESS)
304 return ERROR_SUCCESS;
306 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
307 msiobj_release(&view->hdr);
308 return rc;
311 static UINT ITERATE_UnregisterFonts( MSIRECORD *row, LPVOID param )
313 MSIPACKAGE *package = param;
314 LPWSTR name;
315 LPCWSTR filename;
316 MSIFILE *file;
317 MSICOMPONENT *comp;
318 HKEY hkey1, hkey2;
319 MSIRECORD *uirow;
320 LPWSTR uipath, p;
322 filename = MSI_RecordGetString( row, 1 );
323 file = msi_get_loaded_file( package, filename );
324 if (!file)
326 WARN("unable to find file %s\n", debugstr_w(filename));
327 return ERROR_SUCCESS;
329 comp = msi_get_loaded_component( package, file->Component->Component );
330 if (!comp)
332 WARN("unable to find component %s\n", debugstr_w(file->Component->Component));
333 return ERROR_SUCCESS;
335 comp->Action = msi_get_component_action( package, comp );
336 if (comp->Action != INSTALLSTATE_ABSENT)
338 TRACE("component not scheduled for removal %s\n", debugstr_w(comp->Component));
339 return ERROR_SUCCESS;
342 RegCreateKeyW( HKEY_LOCAL_MACHINE, regfont1, &hkey1 );
343 RegCreateKeyW( HKEY_LOCAL_MACHINE, regfont2, &hkey2 );
345 if (MSI_RecordIsNull( row, 2 ))
346 name = font_name_from_file( package, file->TargetPath );
347 else
348 name = msi_dup_record_field( row, 2 );
350 if (name)
352 RegDeleteValueW( hkey1, name );
353 RegDeleteValueW( hkey2, name );
356 msi_free( name );
357 RegCloseKey( hkey1 );
358 RegCloseKey( hkey2 );
360 /* the UI chunk */
361 uirow = MSI_CreateRecord( 1 );
362 uipath = strdupW( file->TargetPath );
363 p = strrchrW( uipath,'\\' );
364 if (p) p++;
365 else p = uipath;
366 MSI_RecordSetStringW( uirow, 1, p );
367 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
368 msiobj_release( &uirow->hdr );
369 msi_free( uipath );
370 /* FIXME: call msi_ui_progress? */
372 return ERROR_SUCCESS;
375 UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
377 static const WCHAR query[] = {
378 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','F','o','n','t','`',0};
379 MSIQUERY *view;
380 UINT r;
382 if (package->script == SCRIPT_NONE)
383 return msi_schedule_action(package, SCRIPT_INSTALL, szUnregisterFonts);
385 r = MSI_DatabaseOpenViewW( package->db, query, &view );
386 if (r != ERROR_SUCCESS)
387 return ERROR_SUCCESS;
389 r = MSI_IterateRecords( view, NULL, ITERATE_UnregisterFonts, package );
390 msiobj_release( &view->hdr );
391 return r;