msxml4/tests: Copy namespaces as attributes tests.
[wine.git] / dlls / msi / font.c
blob6a4057f69018cbb4f78bcc500b70d292177df38f
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 struct offset_table
33 USHORT uMajorVersion;
34 USHORT uMinorVersion;
35 USHORT uNumOfTables;
36 USHORT uSearchRange;
37 USHORT uEntrySelector;
38 USHORT uRangeShift;
41 struct table_directory
43 char szTag[4]; /* table name */
44 ULONG uCheckSum; /* Check sum */
45 ULONG uOffset; /* Offset from beginning of file */
46 ULONG uLength; /* length of the table in bytes */
49 struct name_table_header
51 USHORT uFSelector; /* format selector. Always 0 */
52 USHORT uNRCount; /* Name Records count */
53 USHORT uStorageOffset; /* Offset for strings storage from start of the table */
56 #define NAME_ID_FULL_FONT_NAME 4
57 #define NAME_ID_VERSION 5
59 struct name_record
61 USHORT uPlatformID;
62 USHORT uEncodingID;
63 USHORT uLanguageID;
64 USHORT uNameID;
65 USHORT uStringLength;
66 USHORT uStringOffset; /* from start of storage area */
69 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
70 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
73 * Code based off of code located here
74 * http://www.codeproject.com/gdi/fontnamefromfile.asp
76 static WCHAR *load_ttf_name_id( MSIPACKAGE *package, const WCHAR *filename, DWORD id )
78 struct table_directory tblDir;
79 BOOL bFound = FALSE;
80 struct offset_table ttOffsetTable;
81 struct name_table_header ttNTHeader;
82 struct name_record ttRecord;
83 DWORD dwRead;
84 HANDLE handle;
85 LPWSTR ret = NULL;
86 int i;
88 if (package)
89 handle = msi_create_file( package, filename, GENERIC_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL );
90 else
91 handle = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );
92 if (handle == INVALID_HANDLE_VALUE)
94 ERR("Unable to open font file %s\n", debugstr_w(filename));
95 return NULL;
98 if (!ReadFile(handle,&ttOffsetTable, sizeof(struct offset_table),&dwRead,NULL))
99 goto end;
101 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
102 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
103 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
105 if ((ttOffsetTable.uMajorVersion != 1 || ttOffsetTable.uMinorVersion != 0) &&
106 (ttOffsetTable.uMajorVersion != 0x4f54 || ttOffsetTable.uMinorVersion != 0x544f))
107 goto end;
109 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
111 if (!ReadFile(handle, &tblDir, sizeof(tblDir), &dwRead, NULL))
112 break;
113 if (memcmp(tblDir.szTag,"name",4)==0)
115 bFound = TRUE;
116 tblDir.uLength = SWAPLONG(tblDir.uLength);
117 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
118 break;
122 if (!bFound)
123 goto end;
125 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
126 if (!ReadFile(handle, &ttNTHeader, sizeof(ttNTHeader), &dwRead, NULL))
127 goto end;
129 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
130 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
131 for(i=0; i<ttNTHeader.uNRCount; i++)
133 if (!ReadFile(handle, &ttRecord, sizeof(ttRecord), &dwRead, NULL))
134 break;
136 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
137 ttRecord.uPlatformID = SWAPWORD(ttRecord.uPlatformID);
138 ttRecord.uEncodingID = SWAPWORD(ttRecord.uEncodingID);
139 if (ttRecord.uNameID == id && ttRecord.uPlatformID == 3 &&
140 (ttRecord.uEncodingID == 0 || ttRecord.uEncodingID == 1))
142 WCHAR *buf;
143 unsigned int i;
145 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
146 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
147 SetFilePointer(handle, tblDir.uOffset + ttRecord.uStringOffset + ttNTHeader.uStorageOffset,
148 NULL, FILE_BEGIN);
149 if (!(buf = calloc(ttRecord.uStringLength, sizeof(WCHAR)))) goto end;
150 dwRead = 0;
151 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
152 if (dwRead % sizeof(WCHAR))
154 free(buf);
155 goto end;
157 for (i = 0; i < dwRead / sizeof(WCHAR); i++) buf[i] = SWAPWORD(buf[i]);
158 ret = wcsdup(buf);
159 free(buf);
160 break;
164 end:
165 CloseHandle(handle);
166 return ret;
169 static WCHAR *font_name_from_file( MSIPACKAGE *package, const WCHAR *filename )
171 WCHAR *name, *ret = NULL;
173 if ((name = load_ttf_name_id( package, filename, NAME_ID_FULL_FONT_NAME )))
175 if (!name[0])
177 WARN("empty font name\n");
178 free( name );
179 return NULL;
181 ret = malloc( wcslen( name ) * sizeof(WCHAR) + sizeof( L" (TrueType)" ) );
182 lstrcpyW( ret, name );
183 lstrcatW( ret, L" (TrueType)" );
184 free( name );
186 return ret;
189 WCHAR *msi_get_font_file_version( MSIPACKAGE *package, const WCHAR *filename )
191 WCHAR *version, *p, *q, *ret = NULL;
193 if ((version = load_ttf_name_id( package, filename, NAME_ID_VERSION )))
195 int len, major = 0, minor = 0;
196 if ((p = wcschr( version, ';' ))) *p = 0;
197 p = version;
198 while (*p && !iswdigit( *p )) p++;
199 if ((q = wcschr( p, '.' )))
201 major = wcstol( p, NULL, 10 );
202 p = ++q;
203 while (*q && iswdigit( *q )) q++;
204 if (!*q || *q == ' ') minor = wcstol( p, NULL, 10 );
205 else major = 0;
207 len = lstrlenW( L"%u.%u.0.0" ) + 20;
208 ret = malloc( len * sizeof(WCHAR) );
209 swprintf( ret, len, L"%u.%u.0.0", major, minor );
210 free( version );
212 return ret;
215 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
217 MSIPACKAGE *package = param;
218 LPWSTR name;
219 LPCWSTR filename;
220 MSIFILE *file;
221 MSICOMPONENT *comp;
222 HKEY hkey1, hkey2;
223 MSIRECORD *uirow;
224 LPWSTR uipath, p;
226 filename = MSI_RecordGetString( row, 1 );
227 file = msi_get_loaded_file( package, filename );
228 if (!file)
230 WARN("unable to find file %s\n", debugstr_w(filename));
231 return ERROR_SUCCESS;
233 comp = msi_get_loaded_component( package, file->Component->Component );
234 if (!comp)
236 WARN("unable to find component %s\n", debugstr_w(file->Component->Component));
237 return ERROR_SUCCESS;
239 comp->Action = msi_get_component_action( package, comp );
240 if (comp->Action != INSTALLSTATE_LOCAL)
242 TRACE("component not scheduled for installation %s\n", debugstr_w(comp->Component));
243 return ERROR_SUCCESS;
246 RegCreateKeyW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts" ,&hkey1 );
247 RegCreateKeyW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts", &hkey2 );
249 if (MSI_RecordIsNull(row,2))
250 name = font_name_from_file( package, file->TargetPath );
251 else
252 name = msi_dup_record_field(row,2);
254 if (name)
256 msi_reg_set_val_str( hkey1, name, file->TargetPath);
257 msi_reg_set_val_str( hkey2, name, file->TargetPath);
260 free(name);
261 RegCloseKey(hkey1);
262 RegCloseKey(hkey2);
264 /* the UI chunk */
265 uirow = MSI_CreateRecord( 1 );
266 uipath = wcsdup( file->TargetPath );
267 p = wcsrchr(uipath,'\\');
268 if (p) p++;
269 else p = uipath;
270 MSI_RecordSetStringW( uirow, 1, p );
271 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
272 msiobj_release( &uirow->hdr );
273 free( uipath );
274 /* FIXME: call msi_ui_progress? */
276 return ERROR_SUCCESS;
279 UINT ACTION_RegisterFonts(MSIPACKAGE *package)
281 MSIQUERY *view;
282 UINT rc;
284 if (package->script == SCRIPT_NONE)
285 return msi_schedule_action(package, SCRIPT_INSTALL, L"RegisterFonts");
287 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Font`", &view);
288 if (rc != ERROR_SUCCESS)
289 return ERROR_SUCCESS;
291 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
292 msiobj_release(&view->hdr);
293 return rc;
296 static UINT ITERATE_UnregisterFonts( MSIRECORD *row, LPVOID param )
298 MSIPACKAGE *package = param;
299 LPWSTR name;
300 LPCWSTR filename;
301 MSIFILE *file;
302 MSICOMPONENT *comp;
303 HKEY hkey1, hkey2;
304 MSIRECORD *uirow;
305 LPWSTR uipath, p;
307 filename = MSI_RecordGetString( row, 1 );
308 file = msi_get_loaded_file( package, filename );
309 if (!file)
311 WARN("unable to find file %s\n", debugstr_w(filename));
312 return ERROR_SUCCESS;
314 comp = msi_get_loaded_component( package, file->Component->Component );
315 if (!comp)
317 WARN("unable to find component %s\n", debugstr_w(file->Component->Component));
318 return ERROR_SUCCESS;
320 comp->Action = msi_get_component_action( package, comp );
321 if (comp->Action != INSTALLSTATE_ABSENT)
323 TRACE("component not scheduled for removal %s\n", debugstr_w(comp->Component));
324 return ERROR_SUCCESS;
327 RegCreateKeyW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", &hkey1 );
328 RegCreateKeyW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts", &hkey2 );
330 if (MSI_RecordIsNull( row, 2 ))
331 name = font_name_from_file( package, file->TargetPath );
332 else
333 name = msi_dup_record_field( row, 2 );
335 if (name)
337 RegDeleteValueW( hkey1, name );
338 RegDeleteValueW( hkey2, name );
341 free( name );
342 RegCloseKey( hkey1 );
343 RegCloseKey( hkey2 );
345 /* the UI chunk */
346 uirow = MSI_CreateRecord( 1 );
347 uipath = wcsdup( file->TargetPath );
348 p = wcsrchr( uipath,'\\' );
349 if (p) p++;
350 else p = uipath;
351 MSI_RecordSetStringW( uirow, 1, p );
352 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
353 msiobj_release( &uirow->hdr );
354 free( uipath );
355 /* FIXME: call msi_ui_progress? */
357 return ERROR_SUCCESS;
360 UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
362 MSIQUERY *view;
363 UINT r;
365 if (package->script == SCRIPT_NONE)
366 return msi_schedule_action(package, SCRIPT_INSTALL, L"UnregisterFonts");
368 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Font`", &view );
369 if (r != ERROR_SUCCESS)
370 return ERROR_SUCCESS;
372 r = MSI_IterateRecords( view, NULL, ITERATE_UnregisterFonts, package );
373 msiobj_release( &view->hdr );
374 return r;