085d400a7b9ca60d4112b1114455e4da40043151
[reactos.git] / reactos / dll / win32 / msi / font.c
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
3 *
4 * Copyright 2004,2005 Aric Stewart 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
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"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(msi);
31
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;
40
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;
47
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;
54
55 typedef struct _tagTT_NAME_RECORD {
56 USHORT uPlatformID;
57 USHORT uEncodingID;
58 USHORT uLanguageID;
59 USHORT uNameID;
60 USHORT uStringLength;
61 USHORT uStringOffset; /* from start of storage area */
62 } TT_NAME_RECORD;
63
64 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
65 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
66
67 static const WCHAR szRegisterFonts[] =
68 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
69
70 /*
71 * Code based off of code located here
72 * http://www.codeproject.com/gdi/fontnamefromfile.asp
73 *
74 * Using string index 4 (full font name) instead of 1 (family name)
75 */
76 static LPWSTR load_ttfname_from(LPCWSTR filename)
77 {
78 TT_TABLE_DIRECTORY tblDir;
79 BOOL bFound = FALSE;
80 TT_OFFSET_TABLE ttOffsetTable;
81 TT_NAME_TABLE_HEADER ttNTHeader;
82 TT_NAME_RECORD ttRecord;
83 DWORD dwRead;
84 HANDLE handle;
85 LPWSTR ret = NULL;
86 int i;
87
88 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
89 FILE_ATTRIBUTE_NORMAL, 0 );
90 if (handle == INVALID_HANDLE_VALUE)
91 {
92 ERR("Unable to open font file %s\n", debugstr_w(filename));
93 return NULL;
94 }
95
96 if (!ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL))
97 goto end;
98
99 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
100 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
101 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
102
103 if (ttOffsetTable.uMajorVersion != 1 || ttOffsetTable.uMinorVersion != 0)
104 goto end;
105
106 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
107 {
108 if (!ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL))
109 break;
110 if (memcmp(tblDir.szTag,"name",4)==0)
111 {
112 bFound = TRUE;
113 tblDir.uLength = SWAPLONG(tblDir.uLength);
114 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
115 break;
116 }
117 }
118
119 if (!bFound)
120 goto end;
121
122 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
123 if (!ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER), &dwRead,NULL))
124 goto end;
125
126 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
127 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
128 bFound = FALSE;
129 for(i=0; i<ttNTHeader.uNRCount; i++)
130 {
131 if (!ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL))
132 break;
133
134 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
135 /* 4 is the Full Font Name */
136 if(ttRecord.uNameID == 4)
137 {
138 int nPos;
139 LPSTR buf;
140 static const char tt[] = " (TrueType)";
141
142 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
143 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
144 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
145 SetFilePointer(handle, tblDir.uOffset +
146 ttRecord.uStringOffset +
147 ttNTHeader.uStorageOffset,
148 NULL, FILE_BEGIN);
149 buf = msi_alloc_zero( ttRecord.uStringLength + 1 + strlen(tt) );
150 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
151 if (strlen(buf) > 0)
152 {
153 strcat(buf,tt);
154 ret = strdupAtoW(buf);
155 msi_free(buf);
156 break;
157 }
158
159 msi_free(buf);
160 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
161 }
162 }
163
164 end:
165 CloseHandle(handle);
166
167 TRACE("Returning fontname %s\n",debugstr_w(ret));
168 return ret;
169 }
170
171 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
172 {
173 MSIPACKAGE *package = param;
174 LPWSTR name;
175 LPCWSTR filename;
176 MSIFILE *file;
177 static const WCHAR regfont1[] =
178 {'S','o','f','t','w','a','r','e','\\',
179 'M','i','c','r','o','s','o','f','t','\\',
180 'W','i','n','d','o','w','s',' ','N','T','\\',
181 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
182 'F','o','n','t','s',0};
183 static const WCHAR regfont2[] =
184 {'S','o','f','t','w','a','r','e','\\',
185 'M','i','c','r','o','s','o','f','t','\\',
186 'W','i','n','d','o','w','s','\\',
187 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
188 'F','o','n','t','s',0};
189 HKEY hkey1;
190 HKEY hkey2;
191 MSIRECORD *uirow;
192 LPWSTR uipath, p;
193
194 filename = MSI_RecordGetString( row, 1 );
195 file = get_loaded_file( package, filename );
196 if (!file)
197 {
198 ERR("Unable to load file\n");
199 return ERROR_SUCCESS;
200 }
201
202 /* check to make sure that component is installed */
203 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
204 {
205 TRACE("Skipping: Component not scheduled for install\n");
206 return ERROR_SUCCESS;
207 }
208
209 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
210 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
211
212 if (MSI_RecordIsNull(row,2))
213 name = load_ttfname_from( file->TargetPath );
214 else
215 name = msi_dup_record_field(row,2);
216
217 if (name)
218 {
219 msi_reg_set_val_str( hkey1, name, file->TargetPath);
220 msi_reg_set_val_str( hkey2, name, file->TargetPath);
221 }
222
223 msi_free(name);
224 RegCloseKey(hkey1);
225 RegCloseKey(hkey2);
226
227 /* the UI chunk */
228 uirow = MSI_CreateRecord( 1 );
229 uipath = strdupW( file->TargetPath );
230 p = strrchrW(uipath,'\\');
231 if (p) p++;
232 else p = uipath;
233 MSI_RecordSetStringW( uirow, 1, p );
234 ui_actiondata( package, szRegisterFonts, uirow);
235 msiobj_release( &uirow->hdr );
236 msi_free( uipath );
237 /* FIXME: call ui_progress? */
238
239 return ERROR_SUCCESS;
240 }
241
242 UINT ACTION_RegisterFonts(MSIPACKAGE *package)
243 {
244 UINT rc;
245 MSIQUERY * view;
246 static const WCHAR ExecSeqQuery[] =
247 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
248 '`','F','o','n','t','`',0};
249
250 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
251 if (rc != ERROR_SUCCESS)
252 {
253 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
254 return ERROR_SUCCESS;
255 }
256
257 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
258 msiobj_release(&view->hdr);
259
260 return ERROR_SUCCESS;
261 }