aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core/Bind/GenerateDatabaseCommand.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core/Bind/GenerateDatabaseCommand.cs')
-rw-r--r--src/WixToolset.Core/Bind/GenerateDatabaseCommand.cs335
1 files changed, 0 insertions, 335 deletions
diff --git a/src/WixToolset.Core/Bind/GenerateDatabaseCommand.cs b/src/WixToolset.Core/Bind/GenerateDatabaseCommand.cs
deleted file mode 100644
index fdf1ab32..00000000
--- a/src/WixToolset.Core/Bind/GenerateDatabaseCommand.cs
+++ /dev/null
@@ -1,335 +0,0 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Bind
4{
5 using System;
6 using System.Collections.Generic;
7 using System.ComponentModel;
8 using System.Globalization;
9 using System.IO;
10 using System.Text;
11 using WixToolset.Data;
12 using WixToolset.Extensibility;
13 using WixToolset.Msi;
14 using WixToolset.Core.Native;
15
16 internal class GenerateDatabaseCommand : ICommand
17 {
18 public int Codepage { private get; set; }
19
20 public IEnumerable<IBinderExtension> Extensions { private get; set; }
21
22 public IEnumerable<IBinderFileManager> FileManagers { private get; set; }
23
24 /// <summary>
25 /// Whether to keep columns added in a transform.
26 /// </summary>
27 public bool KeepAddedColumns { private get; set; }
28
29 public Output Output { private get; set; }
30
31 public string OutputPath { private get; set; }
32
33 public TableDefinitionCollection TableDefinitions { private get; set; }
34
35 public string TempFilesLocation { private get; set; }
36
37 /// <summary>
38 /// Whether to use a subdirectory based on the <paramref name="databaseFile"/> file name for intermediate files.
39 /// </summary>
40 public bool SuppressAddingValidationRows { private get; set; }
41
42 public bool UseSubDirectory { private get; set; }
43
44 public void Execute()
45 {
46 // Add the _Validation rows.
47 if (!this.SuppressAddingValidationRows)
48 {
49 Table validationTable = this.Output.EnsureTable(this.TableDefinitions["_Validation"]);
50
51 foreach (Table table in this.Output.Tables)
52 {
53 if (!table.Definition.Unreal)
54 {
55 // Add the validation rows for this table.
56 table.Definition.AddValidationRows(validationTable);
57 }
58 }
59 }
60
61 // Set the base directory.
62 string baseDirectory = this.TempFilesLocation;
63
64 if (this.UseSubDirectory)
65 {
66 string filename = Path.GetFileNameWithoutExtension(this.OutputPath);
67 baseDirectory = Path.Combine(baseDirectory, filename);
68
69 // make sure the directory exists
70 Directory.CreateDirectory(baseDirectory);
71 }
72
73 try
74 {
75 OpenDatabase type = OpenDatabase.CreateDirect;
76
77 // set special flag for patch files
78 if (OutputType.Patch == this.Output.Type)
79 {
80 type |= OpenDatabase.OpenPatchFile;
81 }
82
83#if DEBUG
84 Console.WriteLine("Opening database at: {0}", this.OutputPath);
85#endif
86
87 using (Database db = new Database(this.OutputPath, type))
88 {
89 // Localize the codepage if a value was specified directly.
90 if (-1 != this.Codepage)
91 {
92 this.Output.Codepage = this.Codepage;
93 }
94
95 // if we're not using the default codepage, import a new one into our
96 // database before we add any tables (or the tables would be added
97 // with the wrong codepage).
98 if (0 != this.Output.Codepage)
99 {
100 this.SetDatabaseCodepage(db, this.Output.Codepage);
101 }
102
103 foreach (Table table in this.Output.Tables)
104 {
105 Table importTable = table;
106 bool hasBinaryColumn = false;
107
108 // Skip all unreal tables other than _Streams.
109 if (table.Definition.Unreal && "_Streams" != table.Name)
110 {
111 continue;
112 }
113
114 // Do not put the _Validation table in patches, it is not needed.
115 if (OutputType.Patch == this.Output.Type && "_Validation" == table.Name)
116 {
117 continue;
118 }
119
120 // The only way to import binary data is to copy it to a local subdirectory first.
121 // To avoid this extra copying and perf hit, import an empty table with the same
122 // definition and later import the binary data from source using records.
123 foreach (ColumnDefinition columnDefinition in table.Definition.Columns)
124 {
125 if (ColumnType.Object == columnDefinition.Type)
126 {
127 importTable = new Table(table.Section, table.Definition);
128 hasBinaryColumn = true;
129 break;
130 }
131 }
132
133 // Create the table via IDT import.
134 if ("_Streams" != importTable.Name)
135 {
136 try
137 {
138 db.ImportTable(this.Output.Codepage, importTable, baseDirectory, this.KeepAddedColumns);
139 }
140 catch (WixInvalidIdtException)
141 {
142 // If ValidateRows finds anything it doesn't like, it throws
143 importTable.ValidateRows();
144
145 // Otherwise we rethrow the InvalidIdt
146 throw;
147 }
148 }
149
150 // insert the rows via SQL query if this table contains object fields
151 if (hasBinaryColumn)
152 {
153 StringBuilder query = new StringBuilder("SELECT ");
154
155 // Build the query for the view.
156 bool firstColumn = true;
157 foreach (ColumnDefinition columnDefinition in table.Definition.Columns)
158 {
159 if (!firstColumn)
160 {
161 query.Append(",");
162 }
163
164 query.AppendFormat(" `{0}`", columnDefinition.Name);
165 firstColumn = false;
166 }
167 query.AppendFormat(" FROM `{0}`", table.Name);
168
169 using (View tableView = db.OpenExecuteView(query.ToString()))
170 {
171 // Import each row containing a stream
172 foreach (Row row in table.Rows)
173 {
174 using (Record record = new Record(table.Definition.Columns.Count))
175 {
176 StringBuilder streamName = new StringBuilder();
177 bool needStream = false;
178
179 // the _Streams table doesn't prepend the table name (or a period)
180 if ("_Streams" != table.Name)
181 {
182 streamName.Append(table.Name);
183 }
184
185 for (int i = 0; i < table.Definition.Columns.Count; i++)
186 {
187 ColumnDefinition columnDefinition = table.Definition.Columns[i];
188
189 switch (columnDefinition.Type)
190 {
191 case ColumnType.Localized:
192 case ColumnType.Preserved:
193 case ColumnType.String:
194 if (columnDefinition.PrimaryKey)
195 {
196 if (0 < streamName.Length)
197 {
198 streamName.Append(".");
199 }
200 streamName.Append((string)row[i]);
201 }
202
203 record.SetString(i + 1, (string)row[i]);
204 break;
205 case ColumnType.Number:
206 record.SetInteger(i + 1, Convert.ToInt32(row[i], CultureInfo.InvariantCulture));
207 break;
208 case ColumnType.Object:
209 if (null != row[i])
210 {
211 needStream = true;
212 try
213 {
214 record.SetStream(i + 1, (string)row[i]);
215 }
216 catch (Win32Exception e)
217 {
218 if (0xA1 == e.NativeErrorCode) // ERROR_BAD_PATHNAME
219 {
220 throw new WixException(WixErrors.FileNotFound(row.SourceLineNumbers, (string)row[i]));
221 }
222 else
223 {
224 throw new WixException(WixErrors.Win32Exception(e.NativeErrorCode, e.Message));
225 }
226 }
227 }
228 break;
229 }
230 }
231
232 // stream names are created by concatenating the name of the table with the values
233 // of the primary key (delimited by periods)
234 // check for a stream name that is more than 62 characters long (the maximum allowed length)
235 if (needStream && MsiInterop.MsiMaxStreamNameLength < streamName.Length)
236 {
237 Messaging.Instance.OnMessage(WixErrors.StreamNameTooLong(row.SourceLineNumbers, table.Name, streamName.ToString(), streamName.Length));
238 }
239 else // add the row to the database
240 {
241 tableView.Modify(ModifyView.Assign, record);
242 }
243 }
244 }
245 }
246
247 // Remove rows from the _Streams table for wixpdbs.
248 if ("_Streams" == table.Name)
249 {
250 table.Rows.Clear();
251 }
252 }
253 }
254
255 // Insert substorages (usually transforms inside a patch or instance transforms in a package).
256 if (0 < this.Output.SubStorages.Count)
257 {
258 using (View storagesView = new View(db, "SELECT `Name`, `Data` FROM `_Storages`"))
259 {
260 foreach (SubStorage subStorage in this.Output.SubStorages)
261 {
262 string transformFile = Path.Combine(this.TempFilesLocation, String.Concat(subStorage.Name, ".mst"));
263
264 // Bind the transform.
265 this.BindTransform(subStorage.Data, transformFile);
266
267 if (Messaging.Instance.EncounteredError)
268 {
269 continue;
270 }
271
272 // add the storage
273 using (Record record = new Record(2))
274 {
275 record.SetString(1, subStorage.Name);
276 record.SetStream(2, transformFile);
277 storagesView.Modify(ModifyView.Assign, record);
278 }
279 }
280 }
281 }
282
283 // We're good, commit the changes to the new database.
284 db.Commit();
285 }
286 }
287 catch (IOException)
288 {
289 // TODO: this error message doesn't seem specific enough
290 throw new WixFileNotFoundException(new SourceLineNumber(this.OutputPath), this.OutputPath);
291 }
292 }
293
294 private void BindTransform(Output transform, string outputPath)
295 {
296 BindTransformCommand command = new BindTransformCommand();
297 command.Extensions = this.Extensions;
298 command.FileManagers = this.FileManagers;
299 command.TempFilesLocation = this.TempFilesLocation;
300 command.Transform = transform;
301 command.OutputPath = outputPath;
302 command.TableDefinitions = this.TableDefinitions;
303 command.Execute();
304 }
305
306 /// <summary>
307 /// Sets the codepage of a database.
308 /// </summary>
309 /// <param name="db">Database to set codepage into.</param>
310 /// <param name="output">Output with the codepage for the database.</param>
311 private void SetDatabaseCodepage(Database db, int codepage)
312 {
313 // write out the _ForceCodepage IDT file
314 string idtPath = Path.Combine(this.TempFilesLocation, "_ForceCodepage.idt");
315 using (StreamWriter idtFile = new StreamWriter(idtPath, false, Encoding.ASCII))
316 {
317 idtFile.WriteLine(); // dummy column name record
318 idtFile.WriteLine(); // dummy column definition record
319 idtFile.Write(codepage);
320 idtFile.WriteLine("\t_ForceCodepage");
321 }
322
323 // try to import the table into the MSI
324 try
325 {
326 db.Import(idtPath);
327 }
328 catch (WixInvalidIdtException)
329 {
330 // the IDT should be valid, so an invalid code page was given
331 throw new WixException(WixErrors.IllegalCodepage(codepage));
332 }
333 }
334 }
335}