diff options
Diffstat (limited to 'apps/plugins/puzzles/winwix.mc')
-rw-r--r-- | apps/plugins/puzzles/winwix.mc | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/apps/plugins/puzzles/winwix.mc b/apps/plugins/puzzles/winwix.mc new file mode 100644 index 0000000000..1a1e620b82 --- /dev/null +++ b/apps/plugins/puzzles/winwix.mc | |||
@@ -0,0 +1,334 @@ | |||
1 | % # Source code for the Puzzles installer. | ||
2 | % # | ||
3 | % # The installer is built using WiX, but this file itself is not valid | ||
4 | % # XML input to WiX's candle.exe; instead, this is a template intended | ||
5 | % # to be processed through the standalone 'mason.pl' script provided | ||
6 | % # with Perl's Mason module. | ||
7 | |||
8 | <%class> | ||
9 | has 'version' => (required => 1); | ||
10 | has 'descfile' => (required => 1); | ||
11 | </%class> | ||
12 | |||
13 | <?xml version="1.0" encoding="utf-8"?> | ||
14 | |||
15 | <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> | ||
16 | |||
17 | % # Product tag. The Id component is set to "*", which causes WiX to | ||
18 | % # make up a new GUID every time it's run, whereas UpgradeCode is set | ||
19 | % # to a fixed GUID. This combination allows Windows to | ||
20 | % # recognise each new installer as different (because of Id) | ||
21 | % # versions of the same underlying thing (because of the common | ||
22 | % # UpgradeCode). | ||
23 | <Product | ||
24 | Name="Simon Tatham's Portable Puzzle Collection" | ||
25 | Manufacturer="Simon Tatham" | ||
26 | Id="*" | ||
27 | UpgradeCode="<% invent_guid('upgradecode') %>" | ||
28 | Language="1033" Codepage="1252" Version="<% $winver %>"> | ||
29 | |||
30 | % # We force the install scope to perMachine, largely because I | ||
31 | % # don't really understand how to make it usefully switchable | ||
32 | % # between the two. If anyone is a WiX expert and does want to | ||
33 | % # install Puzzles locally in a user account, I hope they'll send a | ||
34 | % # well explained patch! | ||
35 | <Package Id="*" Keywords="Installer" | ||
36 | Description="Simon Tatham's Portable Puzzle Collection installer, version <% $.version %>" | ||
37 | Manufacturer="Simon Tatham" | ||
38 | InstallerVersion="100" Languages="1033" | ||
39 | Compressed="yes" SummaryCodepage="1252" | ||
40 | InstallScope="perMachine" /> | ||
41 | |||
42 | % # Permit installing an arbitrary one of these installers | ||
43 | % # over the top of an existing one, whether it's an upgrade or a | ||
44 | % # downgrade. | ||
45 | % # | ||
46 | % # Setting the REINSTALLMODE property to "amus" (from its default | ||
47 | % # of "omus") forces every component replaced by a different | ||
48 | % # version of the installer to be _actually_ reinstalled; the 'o' | ||
49 | % # flag in the default setting breaks the downgrade case by | ||
50 | % # causing Windows to disallow installation of an older version | ||
51 | % # over the top of a newer one - and to do so _silently_, so the | ||
52 | % # installer claims to have worked fine but the files that would have | ||
53 | % # been downgraded aren't there. | ||
54 | <MajorUpgrade AllowDowngrades="yes" MigrateFeatures="yes" /> | ||
55 | <Property Id="REINSTALLMODE" Value="amus"/> | ||
56 | |||
57 | % # Boilerplate | ||
58 | <Media Id="1" Cabinet="puzzles.cab" EmbedCab="yes" /> | ||
59 | |||
60 | % # The actual directory structure and list of 'components' | ||
61 | % # (individual files or shortcuts or additions to PATH) that are | ||
62 | % # installed. | ||
63 | <Directory Id="TARGETDIR" Name="SourceDir"> | ||
64 | <Directory Id="ProgramFilesFolder" Name="PFiles"> | ||
65 | <Directory Id="INSTALLDIR" Name="Simon Tatham's Portable Puzzle Collection"> | ||
66 | |||
67 | % # The following components all install things in the main | ||
68 | % # install directory (implicitly, by being nested where | ||
69 | % # they are in the XML structure). Most of them also put a | ||
70 | % # shortcut in a subdir of the Start menu, though some of | ||
71 | % # the more obscure things like LICENCE are just there for | ||
72 | % # the sake of being _somewhere_ and don't rate a shortcut. | ||
73 | |||
74 | <%method file_component ($filename, $shortcutname)> | ||
75 | % my $filename_id = file_component_name($filename); | ||
76 | <Component Id="File_Component_<% $filename_id %>" | ||
77 | Guid="<% invent_guid('file:' . $filename) %>"> | ||
78 | <File Id="File_<% $filename_id %>" | ||
79 | Source="<% $filename %>" KeyPath="yes"> | ||
80 | % if (defined $shortcutname) { | ||
81 | <Shortcut Id="startmenu_<% $filename_id %>" | ||
82 | Directory="ProgramMenuDir" WorkingDirectory="INSTALLDIR" | ||
83 | Name="<% $shortcutname %>" Advertise="no" /> | ||
84 | % } | ||
85 | </File> | ||
86 | </Component> | ||
87 | </%method> | ||
88 | |||
89 | % for my $exe (@exes) { | ||
90 | <% $.file_component($exe, $names{$exe}) %> | ||
91 | % } | ||
92 | |||
93 | <% $.file_component("puzzles.chm", "Puzzles Manual") %> | ||
94 | <% $.file_component("website.url", "Puzzles Web Site") %> | ||
95 | <% $.file_component("LICENCE") %> | ||
96 | |||
97 | </Directory> | ||
98 | </Directory> | ||
99 | |||
100 | % # This component doesn't actually install anything, but it | ||
101 | % # arranges for the Start Menu _directory_ to be removed again | ||
102 | % # on uninstall. All the actual shortcuts inside the directory | ||
103 | % # are placed by code above here. | ||
104 | <Directory Id="ProgramMenuFolder" Name="Programs"> | ||
105 | <Directory Id="ProgramMenuDir" Name="Simon Tatham's Portable Puzzle Collection"> | ||
106 | <Component Id="ProgramMenuDir" | ||
107 | Guid="<% invent_guid('programmenudir') %>"> | ||
108 | <RemoveFolder Id="ProgramMenuDir" On="uninstall" /> | ||
109 | <RegistryValue Root="HKLM" | ||
110 | Key="Software\SimonTatham\Puzzles\StartMenu" | ||
111 | Type="string" Value="" KeyPath="yes" /> | ||
112 | </Component> | ||
113 | </Directory> | ||
114 | </Directory> | ||
115 | </Directory> | ||
116 | |||
117 | % # Detect an installation of Puzzles made by the old Inno Setup | ||
118 | % # installer, and refuse to run if we find one. I don't know what | ||
119 | % # would happen if you tried anyway, but since they install files | ||
120 | % # at the same pathnames, it surely wouldn't end well. | ||
121 | % # | ||
122 | % # It could be argued that a better approach would be to actually | ||
123 | % # _launch_ the Inno Setup uninstaller automatically at this | ||
124 | % # point (prompting the user first, of course), but I'm not | ||
125 | % # nearly skilled enough with WiX to know how, or even if it's | ||
126 | % # feasible. | ||
127 | <Property Id="LEGACYINNOSETUPINSTALLERNATIVE32PROPERTY"> | ||
128 | <RegistrySearch | ||
129 | Id="LegacyInnoSetupInstallerNative32RegSearch" | ||
130 | Root="HKLM" | ||
131 | Key="SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Simon Tatham's Portable Puzzle Collection_is1" | ||
132 | Name="QuietUninstallString" Type="raw" /> | ||
133 | </Property> | ||
134 | <Property Id="LEGACYINNOSETUPINSTALLER32ON64PROPERTY"> | ||
135 | <RegistrySearch | ||
136 | Id="LegacyInnoSetupInstaller32On64RegSearch" | ||
137 | Root="HKLM" | ||
138 | Key="SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Simon Tatham's Portable Puzzle Collection_is1" | ||
139 | Name="QuietUninstallString" Type="raw" /> | ||
140 | </Property> | ||
141 | <Condition Message="A version of this software is already installed on this system using its old Inno Setup installer. Please uninstall that before running the new installer."> | ||
142 | <![CDATA[Installed OR | ||
143 | (LEGACYINNOSETUPINSTALLERNATIVE32PROPERTY = "" AND | ||
144 | LEGACYINNOSETUPINSTALLER32ON64PROPERTY = "")]]> | ||
145 | </Condition> | ||
146 | |||
147 | % # Separate the installation into 'features', which are parts of | ||
148 | % # the install that can be chosen separately. Trivial: there is only | ||
149 | % # one feature here. | ||
150 | <Feature Id="FilesFeature" Level="1" Absent="disallow" AllowAdvertise="no" | ||
151 | Title="Install puzzle games"> | ||
152 | % for my $exe (@exes) { | ||
153 | <ComponentRef Id="File_Component_<% file_component_name($exe) %>" /> | ||
154 | % } | ||
155 | <ComponentRef Id="File_Component_<% file_component_name("puzzles.chm") %>" /> | ||
156 | <ComponentRef Id="File_Component_<% file_component_name("website.url") %>" /> | ||
157 | <ComponentRef Id="File_Component_<% file_component_name("LICENCE") %>" /> | ||
158 | <ComponentRef Id="ProgramMenuDir" /> | ||
159 | </Feature> | ||
160 | |||
161 | % # Installer user interface. | ||
162 | % # | ||
163 | % # Basically like WixUI_InstallDir, only I've ripped out the EULA. | ||
164 | <UIRef Id="WixUI_Common" /> | ||
165 | |||
166 | <UI> | ||
167 | <TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" /> | ||
168 | <TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12" /> | ||
169 | <TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" /> | ||
170 | |||
171 | <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" /> | ||
172 | <Property Id="WixUI_Mode" Value="InstallDir" /> | ||
173 | |||
174 | <DialogRef Id="BrowseDlg" /> | ||
175 | <DialogRef Id="DiskCostDlg" /> | ||
176 | <DialogRef Id="ErrorDlg" /> | ||
177 | <DialogRef Id="FatalError" /> | ||
178 | <DialogRef Id="FilesInUse" /> | ||
179 | <DialogRef Id="MsiRMFilesInUse" /> | ||
180 | <DialogRef Id="PrepareDlg" /> | ||
181 | <DialogRef Id="ProgressDlg" /> | ||
182 | <DialogRef Id="ResumeDlg" /> | ||
183 | <DialogRef Id="UserExit" /> | ||
184 | |||
185 | <Publish Dialog="BrowseDlg" Control="OK" Event="DoAction" Value="WixUIValidatePath" Order="3">1</Publish> | ||
186 | <Publish Dialog="BrowseDlg" Control="OK" Event="SpawnDialog" Value="InvalidDirDlg" Order="4"><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish> | ||
187 | |||
188 | <Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish> | ||
189 | |||
190 | <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="InstallDirDlg">NOT Installed</Publish> | ||
191 | <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">Installed</Publish> | ||
192 | |||
193 | <Publish Dialog="InstallDirDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg">1</Publish> | ||
194 | <Publish Dialog="InstallDirDlg" Control="Next" Event="SetTargetPath" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish> | ||
195 | <Publish Dialog="InstallDirDlg" Control="Next" Event="DoAction" Value="WixUIValidatePath" Order="2">NOT WIXUI_DONTVALIDATEPATH</Publish> | ||
196 | <Publish Dialog="InstallDirDlg" Control="Next" Event="SpawnDialog" Value="InvalidDirDlg" Order="3"><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish> | ||
197 | <Publish Dialog="InstallDirDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Order="4">WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1"</Publish> | ||
198 | <Publish Dialog="InstallDirDlg" Control="ChangeFolder" Property="_BrowseProperty" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish> | ||
199 | <Publish Dialog="InstallDirDlg" Control="ChangeFolder" Event="SpawnDialog" Value="BrowseDlg" Order="2">1</Publish> | ||
200 | |||
201 | <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="InstallDirDlg" Order="1">NOT Installed</Publish> | ||
202 | <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="2">Installed AND NOT PATCH</Publish> | ||
203 | <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2">Installed AND PATCH</Publish> | ||
204 | |||
205 | <Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish> | ||
206 | |||
207 | <Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish> | ||
208 | <Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish> | ||
209 | <Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg">1</Publish> | ||
210 | |||
211 | % # This ARPNOMODIFY flag prohibits changing the set of | ||
212 | % # installed features, because we don't have any. | ||
213 | <Property Id="ARPNOMODIFY" Value="1" /> | ||
214 | </UI> | ||
215 | |||
216 | % # Glue: tell the install dir part of the UI what id my actual | ||
217 | % # install dir is known by. Otherwise the former won't know how | ||
218 | % # to alter the setting of the latter. | ||
219 | <Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" /> | ||
220 | |||
221 | % # Include my custom installer artwork, created in Buildscr. FIXME: | ||
222 | % # create some! | ||
223 | % # <WixVariable Id="WixUIDialogBmp" Value="msidialog.bmp" /> | ||
224 | % # <WixVariable Id="WixUIBannerBmp" Value="msibanner.bmp" /> | ||
225 | |||
226 | </Product> | ||
227 | </Wix> | ||
228 | |||
229 | <%init> | ||
230 | |||
231 | use Digest::SHA qw(sha512_hex); | ||
232 | use Time::Local; | ||
233 | |||
234 | die "bad date format" if $.version !~ /^(\d{4})(\d{2})(\d{2})/; | ||
235 | my $date = timegm(0,0,0,$3,$2-1,$1); | ||
236 | my $integer_date = int($date / 86400) - 6000; | ||
237 | my $winver = sprintf "0.0.%d.0", $integer_date; | ||
238 | |||
239 | my @exes; | ||
240 | my %names; | ||
241 | { | ||
242 | open my $descfh, "<", $.descfile or die "$.descfile: open: $!\n"; | ||
243 | while (<$descfh>) { | ||
244 | chomp; | ||
245 | my @fields = split /:/; | ||
246 | push @exes, $fields[1]; | ||
247 | $names{$fields[1]} = $fields[2]; | ||
248 | } | ||
249 | close $descfh; | ||
250 | } | ||
251 | |||
252 | sub file_component_name($) { | ||
253 | my ($id) = @_; | ||
254 | $id =~ s!.*\\!!; | ||
255 | $id =~ y!A-Za-z0-9!_!cs; | ||
256 | return $id; | ||
257 | } | ||
258 | |||
259 | sub invent_guid($) { | ||
260 | my ($name) = @_; | ||
261 | |||
262 | # Invent a GUID. We'll need a lot of these in this installer - one | ||
263 | # per puzzle game and a few standard ones - and we'd like to | ||
264 | # arrange for them to be stable between versions of the installer, | ||
265 | # while not having to _manually_ invent one every time. | ||
266 | # | ||
267 | # So we generate our GUIDs by hashing a pile of fixed (but | ||
268 | # originally randomly generated) data with an identifying string | ||
269 | # that acts as source for the particular GUID. For example, | ||
270 | # hashing (fixed_random_data || "upgradecode") produces the GUID | ||
271 | # used as the upgrade code, and (fixed_random_data || | ||
272 | # "installfile:" || filename) gives the GUID for an MSI component | ||
273 | # that installs a specific file. | ||
274 | # | ||
275 | # Hashing _just_ the id strings would clearly be cheating (it's | ||
276 | # quite conceivable that someone might hash the same string for | ||
277 | # another reason and so generate a colliding GUID), but hashing a | ||
278 | # whole SHA-512 data block of random gibberish as well should make | ||
279 | # these GUIDs pseudo-random enough to not collide with anyone | ||
280 | # else's. | ||
281 | |||
282 | my $randdata = pack "N*", | ||
283 | 0xCCAA8D31,0x42931BD9,0xA9D9878A,0x72E4FB9C,0xEA9B11DE,0x4FF17AEC, | ||
284 | 0x1AFA2DEC,0xB662640A,0x780143F5,0xBFFFF0FC,0x01CB46CF,0x832AE842, | ||
285 | 0xBCCDDA12,0x4DB24889,0xEC7A9BCD,0xBCCF70ED,0x85800659,0x8ABA9524, | ||
286 | 0xE484F8D6,0x5CBE55B3,0x95AD9B3D,0x0555F432,0x46737F89,0xE981471C, | ||
287 | 0x4B3419AD,0xD4E49DF4,0xB3EF69DE,0x2A7E391E,0xF3C3D370,0x3EA5E9FC, | ||
288 | 0xB35A57ED,0x52B21099,0x9BD99092,0x7B5097AE,0x4DBE59BD,0x2FCC709B, | ||
289 | 0xC555A779,0x4AE2E5AB,0xB7C74314,0x7F9194CF,0x8FFBCA88,0x46263306, | ||
290 | 0x4C714DF7,0x07FE8CEE,0x28974885,0x0869865D,0xBB5B0EA4,0x4064A928, | ||
291 | 0x28C41910,0x07030758,0x19E66319,0x050C9D4E,0xD79A37FB,0xF232D98B, | ||
292 | 0x0C3E4C25,0xC94F865B,0xB6D86BED,0x87DB718D,0xC65D4C43,0x7C8BBF6A, | ||
293 | 0x9DFDD26A,0x8C478976,0x53E47640,0x263E04AA,0xDD7C5456,0x766BDF50, | ||
294 | 0x86946E34,0xE80D8DE3,0xFB92949E,0x691FDAD0,0x96AB210D,0xB278D60B, | ||
295 | 0x71C7DC6B,0xD49846FC,0x38953F66,0x39777D72,0x4A0F80E5,0xFE1DD1A4, | ||
296 | 0xDA9D191A,0xA32844AD,0x171BFBCC,0xA7D556F6,0xF9F6D944,0xF9687060, | ||
297 | 0xDDDB81D0,0xE9AF4F2F,0xEF84685A,0x8A172492,0x50615EFC,0x20817881, | ||
298 | 0xC3E507E5,0x33189771,0xB9E2EBBD,0x2AAE34A3,0x8D3E7486,0x0A448F13, | ||
299 | 0x94F92A81,0x5150A34F,0x5ED50563,0xAD801A42,0xD0617AFA,0xB78F85F7, | ||
300 | 0x0019D384,0xF0F1C06F,0x6EF8D5B3,0x38092D09,0xC87CD4B3,0xE9D8C84F, | ||
301 | 0xE036648C,0xF2500BD9,0xCF069B5C,0x835326BA,0xCD107B6A,0x64F152B3, | ||
302 | 0xA9663E24,0x33ED5E08,0xC3B24F7E,0xA83205C8,0xA0560F30,0xDFF1226E, | ||
303 | 0xF1A404B7,0x9C2B4EF2,0x62802F88,0xE393A05F,0xC7F72F7B,0x1CD989BD, | ||
304 | 0x725AB516,0xA84F7E39,0xACC3572A,0x820ACB2D,0xAFF5BF06,0x476A2405, | ||
305 | 0x90953482,0x8E8035E1,0x1FB95F6E,0x01FD6766,0x1E63D78E,0xD7D42220, | ||
306 | 0x188D23E4,0x1941BCC5,0xEE1E6487,0x6E197F82,0x32772265,0x9B79D0C8, | ||
307 | 0xB4B617A1,0xCD2475B4,0xDE0F410B,0xE9CF69E4,0x831AC9A4,0xD549A00E, | ||
308 | 0x12ECC561,0x3D636A43,0x1FFFC99A,0xF79401C5,0xAA1D8251,0x84D29609, | ||
309 | 0x5464CB71,0xB28AAE5A,0x4AD934FC,0x347E8A5D,0xC87BCBA0,0x67172E33, | ||
310 | 0xEC70E245,0x4289A9EF,0xA8AF6BA5,0x1528FE0C,0xA87CBFF8,0x79AE1554, | ||
311 | 0xBD59DB9E,0xF1879F94,0x14D7E9F6,0x85196447,0xC4363A67,0x7E02A325, | ||
312 | 0x54051E05,0xABAFE646,0x65D5DF96,0xD3F8173B,0x09D475E7,0x9BF7BD0C, | ||
313 | 0x2DAF371A,0x793D063C,0xA68FD47B,0xBE2500A7,0x0D5071C4,0x08384AC8, | ||
314 | 0xF6CFE74E,0x124A5086,0x03475917,0x47267765,0x56F7DF31,0xE5696381, | ||
315 | 0xEB2B4668,0x78345B5B,0x6E2AFC0F,0x3AD0D43B,0x5C3C2BC9,0x833AB4A0, | ||
316 | 0x1DE2CDBF,0x4DDDCF58,0xEA25D69B,0x36E9B3B0,0xC8B11465,0x066A997E, | ||
317 | 0x9D51C7CD,0x8C6AE686,0xAFB06CE6,0xCC3F3017,0x6E4E4CC0,0x85A34875, | ||
318 | 0x498FE759,0xC24B6332,0xEBCD2257,0xE70FC659,0x439EC788,0xB47F2A06, | ||
319 | 0x696EE8A7,0xF70A31B8,0xECD840F7,0x80AE5E7A,0xC6EDF8AE,0x8165EAFD, | ||
320 | 0x5DAE5ADE,0x9FFD39CE,0xFC6B4C23,0x02BCA024,0xC1497A68,0xD18153EF, | ||
321 | 0xD787EA51,0x91386720,0xBF6E2200,0x98638391,0x144B9148,0x9A554DE1, | ||
322 | 0xA940DC7F,0x37C08265,0x7B782C60,0xC081FDD7,0x62B47201,0x43427563, | ||
323 | 0x1B66E983,0x3DAC0305,0x21E9DEA8,0xA9490EE0,0xE2EFD37D,0x3501F306, | ||
324 | 0x16361BD5,0x668B219D,0x17177844,0x3861A9A4,0x222403B2,0xB29F6714, | ||
325 | 0x7A2A938A,0xBC797418,0x3B241624,0x9163C3F2; | ||
326 | my $digest = sha512_hex($name . "\0" . $randdata); | ||
327 | return sprintf("%s-%s-%04x-%04x-%s", | ||
328 | substr($digest,0,8), | ||
329 | substr($digest,8,4), | ||
330 | 0x4000 | (0xFFF & hex(substr($digest,12,4))), | ||
331 | 0x8000 | (0x3FFF & hex(substr($digest,16,4))), | ||
332 | substr($digest,20,12)); | ||
333 | } | ||
334 | </%init> | ||