evr: Add a forward for MFGetStrideForBitmapInfoHeader().
[wine.git] / dlls / msi / font.c
blob78d384b1654c0bc7d82516bb8ad74cb5ad471c0a
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"
29 WINE_DEFAULT_DEBUG_CHANNEL(msi);
31 typedef struct _tagTT_OFFSET_TABLE {
32 USHORT uMajorVersion;
33 USHORT uMinorVersion;
34 USHORT uNumOfTables;
35 USHORT uSearchRange;
36 USHORT uEntrySelector;
37 USHORT uRangeShift;
38 } TT_OFFSET_TABLE;
40 typedef struct _tagTT_TABLE_DIRECTORY {
41 char szTag[4]; /* table name */
42 ULONG uCheckSum; /* Check sum */
43 ULONG uOffset; /* Offset from beginning of file */
44 ULONG uLength; /* length of the table in bytes */
45 } TT_TABLE_DIRECTORY;
47 typedef struct _tagTT_NAME_TABLE_HEADER {
48 USHORT uFSelector; /* format selector. Always 0 */
49 USHORT uNRCount; /* Name Records count */
50 USHORT uStorageOffset; /* Offset for strings storage,
51 * from start of the table */
52 } TT_NAME_TABLE_HEADER;
54 #define NAME_ID_FULL_FONT_NAME 4
55 #define NAME_ID_VERSION 5
57 typedef struct _tagTT_NAME_RECORD {
58 USHORT uPlatformID;
59 USHORT uEncodingID;
60 USHORT uLanguageID;
61 USHORT uNameID;
62 USHORT uStringLength;
63 USHORT uStringOffset; /* from start of storage area */
64 } TT_NAME_RECORD;
66 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
67 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
70 * Code based off of code located here
71 * http://www.codeproject.com/gdi/fontnamefromfile.asp
73 static WCHAR *load_ttf_name_id( MSIPACKAGE *package, const WCHAR *filename, DWORD id )
75 TT_TABLE_DIRECTORY tblDir;
76 BOOL bFound = FALSE;
77 TT_OFFSET_TABLE ttOffsetTable;
78 TT_NAME_TABLE_HEADER ttNTHeader;
79 TT_NAME_RECORD ttRecord;
80 DWORD dwRead;
81 HANDLE handle;
82 LPWSTR ret = NULL;
83 int i;
85 if (package)
86 handle = msi_create_file( package, filename, GENERIC_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL );
87 else
88 handle = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );
89 if (handle == INVALID_HANDLE_VALUE)
91 ERR("Unable to open font file %s\n", debugstr_w(filename));
92 return NULL;
95 if (!ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL))
96 goto end;
98 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
99 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
100 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
102 if ((ttOffsetTable.uMajorVersion != 1 || ttOffsetTable.uMinorVersion != 0) &&
103 (ttOffsetTable.uMajorVersion != 0x4f54 || ttOffsetTable.uMinorVersion != 0x544f))
104 goto end;
106 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
108 if (!ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL))
109 break;
110 if (memcmp(tblDir.szTag,"name",4)==0)
112 bFound = TRUE;
113 tblDir.uLength = SWAPLONG(tblDir.uLength);
114 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
115 break;
119 if (!bFound)
120 goto end;
122 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
123 if (!ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER), &dwRead,NULL))
124 goto end;
126 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
127 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
128 for(i=0; i<ttNTHeader.uNRCount; i++)
130 if (!ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL))
131 break;
133 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
134 ttRecord.uPlatformID = SWAPWORD(ttRecord.uPlatformID);
135 ttRecord.uEncodingID = SWAPWORD(ttRecord.uEncodingID);
136 if (ttRecord.uNameID == id && ttRecord.uPlatformID == 3 &&
137 (ttRecord.uEncodingID == 0 || ttRecord.uEncodingID == 1))
139 WCHAR *buf;
140 unsigned int i;
142 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
143 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
144 SetFilePointer(handle, tblDir.uOffset + ttRecord.uStringOffset + ttNTHeader.uStorageOffset,
145 NULL, FILE_BEGIN);
146 if (!(buf = msi_alloc_zero( ttRecord.uStringLength + sizeof(WCHAR) ))) goto end;
147 dwRead = 0;
148 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
149 if (dwRead % sizeof(WCHAR))
151 msi_free(buf);
152 goto end;
154 for (i = 0; i < dwRead / sizeof(WCHAR); i++) buf[i] = SWAPWORD(buf[i]);
155 ret = strdupW(buf);
156 msi_free(buf);
157 break;
161 end:
162 CloseHandle(handle);
163 return ret;
166 static WCHAR *font_name_from_file( MSIPACKAGE *package, const WCHAR *filename )
168 WCHAR *name, *ret = NULL;
170 if ((name = load_ttf_name_id( package, filename, NAME_ID_FULL_FONT_NAME )))
172 if (!name[0])
174 WARN("empty font name\n");
175 msi_free( name );
176 return NULL;
178 ret = msi_alloc( (lstrlenW( name ) + lstrlenW( L" (TrueType)" ) + 1 ) * sizeof(WCHAR) );
179 lstrcpyW( ret, name );
180 lstrcatW( ret, L" (TrueType)" );
181 msi_free( name );
183 return ret;
186 WCHAR *msi_get_font_file_version( MSIPACKAGE *package, const WCHAR *filename )
188 WCHAR *version, *p, *q, *ret = NULL;
190 if ((version = load_ttf_name_id( package, filename, NAME_ID_VERSION )))
192 int len, major = 0, minor = 0;
193 if ((p = wcschr( version, ';' ))) *p = 0;
194 p = version;
195 while (*p && !iswdigit( *p )) p++;
196 if ((q = wcschr( p, '.' )))
198 major = wcstol( p, NULL, 10 );
199 p = ++q;
200 while (*q && iswdigit( *q )) q++;
201 if (!*q || *q == ' ') minor = wcstol( p, NULL, 10 );
202 else major = 0;
204 len = lstrlenW( L"%u.%u.0.0" ) + 20;
205 ret = msi_alloc( len * sizeof(WCHAR) );
206 swprintf( ret, len, L"%u.%u.0.0", major, minor );
207 msi_free( version );
209 return ret;
212 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
214 MSIPACKAGE *package = param;
215 LPWSTR name;
216 LPCWSTR filename;
217 MSIFILE *file;
218 MSICOMPONENT *comp;
219 HKEY hkey1, hkey2;
220 MSIRECORD *uirow;
221 LPWSTR uipath, p;
223 filename = MSI_RecordGetString( row, 1 );
224 file = msi_get_loaded_file( package, filename );
225 if (!file)
227 WARN("unable to find file %s\n", debugstr_w(filename));
228 return ERROR_SUCCESS;
230 comp = msi_get_loaded_component( package, file->Component->Component );
231 if (!comp)
233 WARN("unable to find component %s\n", debugstr_w(file->Component->Component));
234 return ERROR_SUCCESS;
236 comp->Action = msi_get_component_action( package, comp );
237 if (comp->Action != INSTALLSTATE_LOCAL)
239 TRACE("component not scheduled for installation %s\n", debugstr_w(comp->Component));
240 return ERROR_SUCCESS;
243 RegCreateKeyW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts" ,&hkey1 );
244 RegCreateKeyW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts", &hkey2 );
246 if (MSI_RecordIsNull(row,2))
247 name = font_name_from_file( package, file->TargetPath );
248 else
249 name = msi_dup_record_field(row,2);
251 if (name)
253 msi_reg_set_val_str( hkey1, name, file->TargetPath);
254 msi_reg_set_val_str( hkey2, name, file->TargetPath);
257 msi_free(name);
258 RegCloseKey(hkey1);
259 RegCloseKey(hkey2);
261 /* the UI chunk */
262 uirow = MSI_CreateRecord( 1 );
263 uipath = strdupW( file->TargetPath );
264 p = wcsrchr(uipath,'\\');
265 if (p) p++;
266 else p = uipath;
267 MSI_RecordSetStringW( uirow, 1, p );
268 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
269 msiobj_release( &uirow->hdr );
270 msi_free( uipath );
271 /* FIXME: call msi_ui_progress? */
273 return ERROR_SUCCESS;
276 UINT ACTION_RegisterFonts(MSIPACKAGE *package)
278 MSIQUERY *view;
279 UINT rc;
281 if (package->script == SCRIPT_NONE)
282 return msi_schedule_action(package, SCRIPT_INSTALL, L"RegisterFonts");
284 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Font`", &view);
285 if (rc != ERROR_SUCCESS)
286 return ERROR_SUCCESS;
288 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
289 msiobj_release(&view->hdr);
290 return rc;
293 static UINT ITERATE_UnregisterFonts( MSIRECORD *row, LPVOID param )
295 MSIPACKAGE *package = param;
296 LPWSTR name;
297 LPCWSTR filename;
298 MSIFILE *file;
299 MSICOMPONENT *comp;
300 HKEY hkey1, hkey2;
301 MSIRECORD *uirow;
302 LPWSTR uipath, p;
304 filename = MSI_RecordGetString( row, 1 );
305 file = msi_get_loaded_file( package, filename );
306 if (!file)
308 WARN("unable to find file %s\n", debugstr_w(filename));
309 return ERROR_SUCCESS;
311 comp = msi_get_loaded_component( package, file->Component->Component );
312 if (!comp)
314 WARN("unable to find component %s\n", debugstr_w(file->Component->Component));
315 return ERROR_SUCCESS;
317 comp->Action = msi_get_component_action( package, comp );
318 if (comp->Action != INSTALLSTATE_ABSENT)
320 TRACE("component not scheduled for removal %s\n", debugstr_w(comp->Component));
321 return ERROR_SUCCESS;
324 RegCreateKeyW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", &hkey1 );
325 RegCreateKeyW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts", &hkey2 );
327 if (MSI_RecordIsNull( row, 2 ))
328 name = font_name_from_file( package, file->TargetPath );
329 else
330 name = msi_dup_record_field( row, 2 );
332 if (name)
334 RegDeleteValueW( hkey1, name );
335 RegDeleteValueW( hkey2, name );
338 msi_free( name );
339 RegCloseKey( hkey1 );
340 RegCloseKey( hkey2 );
342 /* the UI chunk */
343 uirow = MSI_CreateRecord( 1 );
344 uipath = strdupW( file->TargetPath );
345 p = wcsrchr( uipath,'\\' );
346 if (p) p++;
347 else p = uipath;
348 MSI_RecordSetStringW( uirow, 1, p );
349 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
350 msiobj_release( &uirow->hdr );
351 msi_free( uipath );
352 /* FIXME: call msi_ui_progress? */
354 return ERROR_SUCCESS;
357 UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
359 MSIQUERY *view;
360 UINT r;
362 if (package->script == SCRIPT_NONE)
363 return msi_schedule_action(package, SCRIPT_INSTALL, L"UnregisterFonts");
365 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Font`", &view );
366 if (r != ERROR_SUCCESS)
367 return ERROR_SUCCESS;
369 r = MSI_IterateRecords( view, NULL, ITERATE_UnregisterFonts, package );
370 msiobj_release( &view->hdr );
371 return r;