/// <summary> /// Saves an output to a path on disk. /// </summary> /// <param name="path">Path to save output file to on disk.</param> /// <param name="binderFileManager">If provided, the binder file manager is used to bind files into the output.</param> /// <param name="wixVariableResolver">The Wix variable resolver.</param> /// <param name="tempFilesLocation">Location for temporary files.</param> public void Save(string path, BinderFileManager binderFileManager, WixVariableResolver wixVariableResolver, string tempFilesLocation) { FileMode fileMode = FileMode.Create; // Assure the location to output the xml exists Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(path))); // Check if there was a cab on the output when it was created if (SaveCab(path, binderFileManager, wixVariableResolver, tempFilesLocation)) { fileMode = FileMode.Append; } // save the xml using (FileStream fs = new FileStream(path, fileMode)) { XmlWriter writer = null; try { writer = new XmlTextWriter(fs, System.Text.Encoding.UTF8); writer.WriteStartDocument(); this.Persist(writer); writer.WriteEndDocument(); } finally { if (null != writer) { writer.Close(); } } } }
private string ParseComponentElement(XmlNode node, ComplexReferenceParentType parentType, string parentId, string parentLanguage, int diskId, string directoryId, string srcPath) { SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); int bits = 0; int comPlusBits = CompilerCore.IntegerNotSet; string condition = null; bool encounteredODBCDataSource = false; bool explicitWin64 = false; int files = 0; string guid = "*"; string autoId = Compiler.DefaultComponentIdPlaceholder; // placeholder id for defaulting Component/@Id to keypath id. string id = Compiler.DefaultComponentIdPlaceholderWixVariable; int keyBits = 0; bool keyFound = false; string keyPath = null; bool shouldAddCreateFolder = false; bool win64 = false; bool multiInstance = false; string symbols = null; string feature = null; foreach (XmlAttribute attrib in node.Attributes) { if (0 == attrib.NamespaceURI.Length || attrib.NamespaceURI == this.schema.TargetNamespace) { switch (attrib.LocalName) { case "Id": id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; case "ComPlusFlags": comPlusBits = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); break; case "DisableRegistryReflection": if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { bits |= MsiInterop.MsidbComponentAttributesDisableRegistryReflection; } break; case "Directory": if (null != directoryId) { this.core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name, attrib.Name, "Directory")); } directoryId = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); this.core.CreateWixSimpleReferenceRow(sourceLineNumbers, "Directory", directoryId); break; case "DiskId": diskId = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, short.MaxValue); break; case "Feature": feature = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; case "Guid": guid = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, true, true); break; case "KeyPath": if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { keyFound = true; keyPath = null; keyBits = 0; shouldAddCreateFolder = true; } break; case "Location": string location = this.core.GetAttributeValue(sourceLineNumbers, attrib); if (0 < location.Length) { Wix.Component.LocationType locationType = Wix.Component.ParseLocationType(location); switch (locationType) { case Wix.Component.LocationType.either: bits |= MsiInterop.MsidbComponentAttributesOptional; break; case Wix.Component.LocationType.local: // this is the default break; case Wix.Component.LocationType.source: bits |= MsiInterop.MsidbComponentAttributesSourceOnly; break; default: this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name, attrib.Name, "either", "local", "source")); break; } } break; case "MultiInstance": multiInstance = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; case "NeverOverwrite": if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { bits |= MsiInterop.MsidbComponentAttributesNeverOverwrite; } break; case "Permanent": if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { bits |= MsiInterop.MsidbComponentAttributesPermanent; } break; case "Shared": if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { bits |= MsiInterop.MsidbComponentAttributesShared; } break; case "SharedDllRefCount": if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { bits |= MsiInterop.MsidbComponentAttributesSharedDllRefCount; } break; case "Transitive": if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { bits |= MsiInterop.MsidbComponentAttributesTransitive; } break; case "UninstallWhenSuperseded": if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { bits |= MsiInterop.MsidbComponentAttributesUninstallOnSupersedence; } break; case "Win64": explicitWin64 = true; if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { bits |= MsiInterop.MsidbComponentAttributes64bit; win64 = true; } break; default: this.core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.core.ParseExtensionAttribute(sourceLineNumbers, (XmlElement)node, attrib); } } if (!explicitWin64 && (Platform.IA64 == CurrentPlatform || Platform.X64 == CurrentPlatform)) { bits |= MsiInterop.MsidbComponentAttributes64bit; win64 = true; } if (null == directoryId) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Directory")); } if (String.IsNullOrEmpty(guid) && MsiInterop.MsidbComponentAttributesShared == (bits & MsiInterop.MsidbComponentAttributesShared)) { this.core.OnMessage(WixErrors.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name, "Shared", "yes", "Guid", "")); } if (String.IsNullOrEmpty(guid) && MsiInterop.MsidbComponentAttributesPermanent == (bits & MsiInterop.MsidbComponentAttributesPermanent)) { this.core.OnMessage(WixErrors.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name, "Permanent", "yes", "Guid", "")); } if (null != feature) { if (this.compilingModule) { this.core.OnMessage(WixErrors.IllegalAttributeInMergeModule(sourceLineNumbers, node.Name, "Feature")); } else { if (ComplexReferenceParentType.Feature == parentType || ComplexReferenceParentType.FeatureGroup == parentType) { this.core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name, "Feature", node.ParentNode.LocalName)); } else { this.core.CreateComplexReference(sourceLineNumbers, ComplexReferenceParentType.Feature, feature, null, ComplexReferenceChildType.Component, id, true); } } } foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { YesNoType keyPathSet = YesNoType.NotSet; string keyPossible = null; int keyBit = 0; if (child.NamespaceURI == this.schema.TargetNamespace) { switch (child.LocalName) { case "AppId": this.ParseAppIdElement(child, id, YesNoType.NotSet, null, null, null); break; case "Category": this.ParseCategoryElement(child, id); break; case "Class": this.ParseClassElement(child, id, YesNoType.NotSet, null, null, null, null); break; case "Condition": if (null != condition) { SourceLineNumberCollection childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); this.core.OnMessage(WixErrors.TooManyChildren(childSourceLineNumbers, node.Name, child.Name)); } condition = this.ParseConditionElement(child, node.LocalName, null, null); break; case "CopyFile": this.ParseCopyFileElement(child, id, null); break; case "CreateFolder": string createdFolder = this.ParseCreateFolderElement(child, id, directoryId, win64); if (directoryId == createdFolder) { shouldAddCreateFolder = false; } break; case "Environment": this.ParseEnvironmentElement(child, id); break; case "Extension": this.ParseExtensionElement(child, id, YesNoType.NotSet, null); break; case "File": keyPathSet = this.ParseFileElement(child, id, directoryId, diskId, srcPath, out keyPossible, win64, guid); if (null != keyPossible) { keyBit = 0; } files++; break; case "IniFile": this.ParseIniFileElement(child, id); break; case "Interface": this.ParseInterfaceElement(child, id, null, null, null, null); break; case "IsolateComponent": this.ParseIsolateComponentElement(child, id); break; case "ODBCDataSource": keyPathSet = this.ParseODBCDataSource(child, id, null, out keyPossible); keyBit = MsiInterop.MsidbComponentAttributesODBCDataSource; encounteredODBCDataSource = true; break; case "ODBCDriver": this.ParseODBCDriverOrTranslator(child, id, null, this.tableDefinitions["ODBCDriver"]); break; case "ODBCTranslator": this.ParseODBCDriverOrTranslator(child, id, null, this.tableDefinitions["ODBCTranslator"]); break; case "ProgId": bool foundExtension = false; this.ParseProgIdElement(child, id, YesNoType.NotSet, null, null, null, ref foundExtension, YesNoType.NotSet); break; case "Registry": keyPathSet = this.ParseRegistryElement(child, id, CompilerCore.IntegerNotSet, null, win64, out keyPossible); keyBit = MsiInterop.MsidbComponentAttributesRegistryKeyPath; break; case "RegistryKey": keyPathSet = this.ParseRegistryKeyElement(child, id, CompilerCore.IntegerNotSet, null, win64, out keyPossible); keyBit = MsiInterop.MsidbComponentAttributesRegistryKeyPath; break; case "RegistryValue": keyPathSet = this.ParseRegistryValueElement(child, id, CompilerCore.IntegerNotSet, null, win64, out keyPossible); keyBit = MsiInterop.MsidbComponentAttributesRegistryKeyPath; break; case "RemoveFile": this.ParseRemoveFileElement(child, id, directoryId); break; case "RemoveFolder": this.ParseRemoveFolderElement(child, id, directoryId); break; case "RemoveRegistryKey": this.ParseRemoveRegistryKeyElement(child, id); break; case "RemoveRegistryValue": this.ParseRemoveRegistryValueElement(child, id); break; case "ReserveCost": this.ParseReserveCostElement(child, id, directoryId); break; case "ServiceConfig": this.ParseServiceConfigElement(child, id, null); break; case "ServiceConfigFailureActions": this.ParseServiceConfigFailureActionsElement(child, id, null); break; case "ServiceControl": this.ParseServiceControlElement(child, id); break; case "ServiceInstall": this.ParseServiceInstallElement(child, id, win64); break; case "Shortcut": this.ParseShortcutElement(child, id, node.LocalName, directoryId, YesNoType.No); break; case "SymbolPath": if (null != symbols) { symbols += ";" + this.ParseSymbolPathElement(child); } else { symbols = this.ParseSymbolPathElement(child); } break; case "TypeLib": this.ParseTypeLibElement(child, id, null, win64); break; default: this.core.UnexpectedElement(node, child); break; } } else { CompilerExtension.ComponentKeypathType keyType = this.core.ParseExtensionElement(sourceLineNumbers, (XmlElement)node, (XmlElement)child, ref keyPossible, id, directoryId, win64.ToString()); // CompilerExtension must return a key path type, so the component key path is either set or not (no automatic selection). keyPathSet = CompilerExtension.ComponentKeypathType.None != keyType ? YesNoType.Yes : YesNoType.No; if (CompilerExtension.ComponentKeypathType.Registry == keyType || CompilerExtension.ComponentKeypathType.RegistryFormatted == keyType) { keyBit = MsiInterop.MsidbComponentAttributesRegistryKeyPath; } } // Verify that either the key path is not set, or it is set along with a key path ID. Debug.Assert(YesNoType.Yes != keyPathSet || (YesNoType.Yes == keyPathSet && null != keyPossible)); if (keyFound && YesNoType.Yes == keyPathSet) { this.core.OnMessage(WixErrors.ComponentMultipleKeyPaths(sourceLineNumbers, node.Name, "KeyPath", "yes", "File", "RegistryValue", "ODBCDataSource")); } // if a possible KeyPath has been found and that value was explicitly set as // the KeyPath of the component, set it now. Alternatively, if a possible // KeyPath has been found and no KeyPath has been previously set, use this // value as the default KeyPath of the component if (null != keyPossible && (YesNoType.Yes == keyPathSet || (YesNoType.NotSet == keyPathSet && null == keyPath && !keyFound))) { keyFound = YesNoType.Yes == keyPathSet; keyPath = keyPossible; keyBits = keyBit; } } } if (shouldAddCreateFolder) { Row row = this.core.CreateRow(sourceLineNumbers, "CreateFolder"); row[0] = directoryId; row[1] = id; } // check for conditions that exclude this component from using generated guids bool isGeneratableGuidOk = "*" == guid; if (isGeneratableGuidOk) { if (encounteredODBCDataSource) { this.core.OnMessage(WixErrors.IllegalComponentWithAutoGeneratedGuid(sourceLineNumbers)); isGeneratableGuidOk = false; } if (0 != files && MsiInterop.MsidbComponentAttributesRegistryKeyPath == keyBits) { this.core.OnMessage(WixErrors.IllegalComponentWithAutoGeneratedGuid(sourceLineNumbers, true)); isGeneratableGuidOk = false; } } // check for implicit KeyPath which can easily be accidentally changed if (this.showPedanticMessages && !keyFound && !isGeneratableGuidOk) { this.core.OnMessage(WixErrors.ImplicitComponentKeyPath(sourceLineNumbers, id)); } // if there isn't an @Id attribute value, replace the placeholder with the id of the keypath. // either an explicit KeyPath="yes" attribute must be specified or requirements for // generatable guid must be met. if (Compiler.DefaultComponentIdPlaceholderWixVariable == id) { if (isGeneratableGuidOk || keyFound && !String.IsNullOrEmpty(keyPath)) { id = keyPath; WixVariableResolver resolver = new WixVariableResolver(); resolver.AddVariable(autoId, keyPath); foreach (Table table in this.core.ActiveSection.Tables) { foreach (Row row in table.Rows) { foreach (Field field in row.Fields) { if (field.Data is string) { bool isDefault = false; bool delayedResolve = false; field.Data = resolver.ResolveVariables(row.SourceLineNumbers, (string)field.Data, false, false, ref isDefault, ref delayedResolve); } } } } } else { this.core.OnMessage(WixErrors.CannotDefaultComponentId(sourceLineNumbers)); } } // If an id was not determined by now, we have to error. if (null == id) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Id")); } // finally add the Component table row if (!this.core.EncounteredError) { Row row = this.core.CreateRow(sourceLineNumbers, "Component"); row[0] = id; row[1] = guid; row[2] = directoryId; row[3] = bits | keyBits; row[4] = condition; row[5] = keyPath; if (multiInstance) { Row instanceComponentRow = this.core.CreateRow(sourceLineNumbers, "WixInstanceComponent"); instanceComponentRow[0] = id; } if (null != symbols) { Row symbolRow = this.core.CreateRow(sourceLineNumbers, "WixPatchSymbolPaths"); symbolRow[0] = "Component"; symbolRow[1] = id; symbolRow[2] = symbols; } // Complus if (CompilerCore.IntegerNotSet != comPlusBits) { row = this.core.CreateRow(sourceLineNumbers, "Complus"); row[0] = id; row[1] = comPlusBits; } // if this is a module, automatically add this component to the references to ensure it gets in the ModuleComponents table if (this.compilingModule) { this.core.CreateComplexReference(sourceLineNumbers, ComplexReferenceParentType.Module, this.activeName, this.activeLanguage, ComplexReferenceChildType.Component, id, false); } else if (ComplexReferenceParentType.Unknown != parentType && null != parentId) // if parent was provided, add a complex reference to that. { // If the Component is defined directly under a feature, then mark the complex reference primary. this.core.CreateComplexReference(sourceLineNumbers, parentType, parentId, parentLanguage, ComplexReferenceChildType.Component, id, ComplexReferenceParentType.Feature == parentType); } } return id; }
/// <summary> /// Saves a library to a path on disk. /// </summary> /// <param name="path">Path to save library file to on disk.</param> /// <param name="binderFileManager">If provided, the binder file manager is used to bind files into the library.</param> /// <param name="wixVariableResolver">The Wix variable resolver.</param> public void Save(string path, BinderFileManager binderFileManager, WixVariableResolver wixVariableResolver) { FileMode fileMode = FileMode.Create; StringCollection fileIds = new StringCollection(); StringCollection files = new StringCollection(); int index = 0; // resolve paths to files and create the library cabinet file foreach (Section section in this.sections) { foreach (Table table in section.Tables) { foreach (Row row in table.Rows) { foreach (Field field in row.Fields) { ObjectField objectField = field as ObjectField; if (null != objectField) { if (null != binderFileManager && null != objectField.Data) { string cabinetFileId = (index++).ToString(CultureInfo.InvariantCulture); // resolve wix variables string resolvedValue = wixVariableResolver.ResolveVariables(row.SourceLineNumbers, (string)objectField.Data, false); files.Add(binderFileManager.ResolveFile(resolvedValue, table.Name, row.SourceLineNumbers, BindStage.Normal)); // File was successfully resolved so track this cabient file id. objectField.CabinetFileId = cabinetFileId; fileIds.Add(cabinetFileId); } else // clear out a previous cabinet file id value { objectField.CabinetFileId = null; } } } } } } // do not save the library if errors were found while resolving object paths if (wixVariableResolver.EncounteredError) { return; } // create the cabinet file if (0 < fileIds.Count) { using (WixCreateCab cab = new WixCreateCab(Path.GetFileName(path), Path.GetDirectoryName(path), fileIds.Count, 0, 0, CompressionLevel.Mszip)) { for (int i = 0; i < fileIds.Count; i++) { cab.AddFile(files[i], fileIds[i]); } cab.Complete(); } // append the library xml to the end of the newly created cabinet file fileMode = FileMode.Append; } // Assure the location to output the lib exists Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(path))); // save the xml using (FileStream fs = new FileStream(path, fileMode)) { XmlWriter writer = null; try { writer = new XmlTextWriter(fs, System.Text.Encoding.UTF8); writer.WriteStartDocument(); this.Persist(writer); writer.WriteEndDocument(); } finally { if (null != writer) { writer.Close(); } } } }
/// <summary> /// Saves an output to a path on disk. /// </summary> /// <param name="path">Path to save output file to on disk.</param> /// <param name="binderExtension">If provided, the binder extension is used to bind files into the output.</param> /// <param name="wixVariableResolver">The Wix variable resolver.</param> /// <param name="tempFilesLocation">Location for temporary files.</param> public void Save(string path, BinderExtension binderExtension, WixVariableResolver wixVariableResolver, string tempFilesLocation) { FileMode fileMode = FileMode.Create; // Check if there was a cab on the wixout when it was created if (null != this.cabPath) { // There was already a cab on the wixout when it was loaded. Reuse that one. File.Copy(this.cabPath, path, true); if (null != this.tempFileCollection) { this.tempFileCollection.Delete(); } fileMode = FileMode.Append; } else { Hashtable cabinets = new Hashtable(); StringCollection fileIds = new StringCollection(); StringCollection files = new StringCollection(); int index = 0; // resolve paths to files and create the output cabinet file foreach (Section section in this.sections) { foreach (Table table in section.Tables) { foreach (Row row in table.Rows) { foreach (Field field in row.Fields) { ObjectField objectField = field as ObjectField; if (null != objectField && null != objectField.Data) { string file = null; bool isDefault = true; // resolve localization and wix variables objectField.Data = wixVariableResolver.ResolveVariables(null, row.SourceLineNumbers, (string)objectField.Data, false, ref isDefault); // do not save the output if errors were found while resolving object paths if (wixVariableResolver.EncounteredError) { return; } // file is compressed in a cabinet (and not modified above) if (null != objectField.CabinetFileId && isDefault) { // index cabinets that have not been previously encountered if (!cabinets.ContainsKey(objectField.BaseUri)) { Uri baseUri = new Uri(objectField.BaseUri); string localFileNameWithoutExtension = Path.GetFileNameWithoutExtension(baseUri.LocalPath); string extractedDirectoryName = String.Format(CultureInfo.InvariantCulture, "cab_{0}_{1}", cabinets.Count, localFileNameWithoutExtension); // index the cabinet file's base URI (source location) and extracted directory cabinets.Add(objectField.BaseUri, Path.Combine(tempFilesLocation, extractedDirectoryName)); } // set the path to the file once its extracted from the cabinet file = Path.Combine((string)cabinets[objectField.BaseUri], objectField.CabinetFileId); } else if (null != binderExtension) { file = binderExtension.ResolveFile((string)objectField.Data); } // add the file to the list of files to go in the cabinet if (null != file) { string cabinetFileId = (index++).ToString(CultureInfo.InvariantCulture); objectField.CabinetFileId = cabinetFileId; fileIds.Add(cabinetFileId); files.Add(file); } } } } } } // extract files that come from cabinet files if (0 < cabinets.Count) { // ensure the temporary directory exists Directory.CreateDirectory(tempFilesLocation); foreach (DictionaryEntry cabinet in cabinets) { Uri baseUri = new Uri((string)cabinet.Key); string localPath; if ("embeddedresource" == baseUri.Scheme) { int bytesRead; byte[] buffer = new byte[512]; string originalLocalPath = Path.GetFullPath(baseUri.LocalPath.Substring(1)); string resourceName = baseUri.Fragment.Substring(1); Assembly assembly = Assembly.LoadFile(originalLocalPath); localPath = String.Concat(cabinet.Value, ".cab"); using (FileStream fs = File.OpenWrite(localPath)) { using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName)) { while (0 < (bytesRead = resourceStream.Read(buffer, 0, buffer.Length))) { fs.Write(buffer, 0, bytesRead); } } } } else // normal file { localPath = baseUri.LocalPath; } // extract the cabinet's files into a temporary directory Directory.CreateDirectory((string)cabinet.Value); using (WixExtractCab extractCab = new WixExtractCab()) { extractCab.Extract(localPath, (string)cabinet.Value); } } } // create the cabinet file if (0 < fileIds.Count) { try { using (WixCreateCab cab = new WixCreateCab(Path.GetFileName(path), Path.GetDirectoryName(path), 0, 0, CompressionLevel.Mszip)) { for (int i = 0; i < fileIds.Count; i++) { cab.AddFile(files[i], fileIds[i]); } } } catch (FileNotFoundException e) { throw new WixException(WixErrors.FileNotFound(null, e.FileName)); } // append the output xml to the end of the newly created cabinet file fileMode = FileMode.Append; } } // Assure the location to output the xml exists Directory.CreateDirectory(Path.GetDirectoryName(path)); // save the xml using (FileStream fs = new FileStream(path, fileMode)) { XmlWriter writer = null; try { writer = new XmlTextWriter(fs, System.Text.Encoding.UTF8); writer.WriteStartDocument(); this.Persist(writer); writer.WriteEndDocument(); } finally { if (null != writer) { writer.Close(); } } } }
/// <summary> /// Saves a library to a path on disk. /// </summary> /// <param name="path">Path to save library file to on disk.</param> /// <param name="binderExtension">If provided, the binder extension is used to bind files into the library.</param> /// <param name="wixVariableResolver">The Wix variable resolver.</param> public void Save(string path, BinderExtension binderExtension, WixVariableResolver wixVariableResolver) { FileMode fileMode = FileMode.Create; StringCollection fileIds = new StringCollection(); StringCollection files = new StringCollection(); int index = 0; // resolve paths to files and create the library cabinet file foreach (Section section in this.sections) { foreach (Table table in section.Tables) { foreach (Row row in table.Rows) { foreach (Field field in row.Fields) { ObjectField objectField = field as ObjectField; if (null != objectField) { if (null != binderExtension && null != objectField.Data) { string cabinetFileId = (index++).ToString(CultureInfo.InvariantCulture); objectField.CabinetFileId = cabinetFileId; fileIds.Add(cabinetFileId); // resolve wix variables string resolvedValue = wixVariableResolver.ResolveVariables(null, row.SourceLineNumbers, (string)objectField.Data, false); files.Add(binderExtension.ResolveFile(resolvedValue)); } else // clear out a previous cabinet file id value { objectField.CabinetFileId = null; } } } } } } // do not save the library if errors were found while resolving object paths if (wixVariableResolver.EncounteredError) { return; } // create the cabinet file if (0 < fileIds.Count) { try { using (WixCreateCab cab = new WixCreateCab(Path.GetFileName(path), Path.GetDirectoryName(path), 0, 0, CompressionLevel.Mszip)) { for (int i = 0; i < fileIds.Count; i++) { cab.AddFile(files[i], fileIds[i]); } } } catch (FileNotFoundException e) { throw new WixException(WixErrors.FileNotFound(null, e.FileName)); } // append the library xml to the end of the newly created cabinet file fileMode = FileMode.Append; } // save the xml using (FileStream fs = new FileStream(path, fileMode)) { XmlWriter writer = null; try { writer = new XmlTextWriter(fs, System.Text.Encoding.UTF8); writer.WriteStartDocument(); this.Persist(writer); writer.WriteEndDocument(); } finally { if (null != writer) { writer.Close(); } } } }
/// <summary> /// Resolves paths to files. /// </summary> /// <param name="sectionTables">TableCollection of tables to process</param> /// <param name="binderFileManager">If provided, the binder file manager is used to bind files into the output.</param> /// <param name="wixVariableResolver">The Wix variable resolver.</param> /// <param name="tempFilesLocation">Location for temporary files.</param> /// <param name="cabinets">Hash of source cabinets.</param> /// <param name="fileIds">Collection of CabinetFileIds.</param> /// <param name="files">Collection of file paths from compressed files.</param> /// <param name="index">CabinetFileId generator.</param> public static void ResolveSectionFiles(TableCollection sectionTables, BinderFileManager binderFileManager, WixVariableResolver wixVariableResolver, string tempFilesLocation, Hashtable cabinets, StringCollection fileIds, StringCollection files, ref int index) { foreach (Table table in sectionTables) { foreach (Row row in table.Rows) { foreach (Field field in row.Fields) { ObjectField objectField = field as ObjectField; if (null != objectField && null != objectField.Data) { string file = null; string previousFile = null; bool isDefault = true; bool isPreviousDefault = true; // resolve localization and wix variables if there is a file manager that would use the value // if it was different, otherwise we just don't care so skip the whole variable resolution thing. if (null != wixVariableResolver && null != binderFileManager) { objectField.Data = wixVariableResolver.ResolveVariables(row.SourceLineNumbers, (string)objectField.Data, false, ref isDefault); if (null != objectField.PreviousData) { objectField.PreviousData = wixVariableResolver.ResolveVariables(row.SourceLineNumbers, objectField.PreviousData, false, ref isPreviousDefault); } // do not save the output if errors were found while resolving object paths if (wixVariableResolver.EncounteredError) { return; } } // file is compressed in a cabinet (and not modified above) if (null != objectField.CabinetFileId && isDefault) { // index cabinets that have not been previously encountered if (!cabinets.ContainsKey(objectField.BaseUri)) { Uri baseUri = new Uri(objectField.BaseUri); string localFileNameWithoutExtension = Path.GetFileNameWithoutExtension(baseUri.LocalPath); string extractedDirectoryName = String.Format(CultureInfo.InvariantCulture, "cab_{0}_{1}", cabinets.Count, localFileNameWithoutExtension); // index the cabinet file's base URI (source location) and extracted directory cabinets.Add(objectField.BaseUri, Path.Combine(tempFilesLocation, extractedDirectoryName)); } // set the path to the file once its extracted from the cabinet file = Path.Combine((string)cabinets[objectField.BaseUri], objectField.CabinetFileId); } else if (null != binderFileManager) { file = binderFileManager.ResolveFile((string)objectField.Data, table.Name, row.SourceLineNumbers, BindStage.Normal); } // add the file to the list of files to go in the cabinet if (null != file) { string cabinetFileId = (index++).ToString(CultureInfo.InvariantCulture); objectField.CabinetFileId = cabinetFileId; fileIds.Add(cabinetFileId); files.Add(file); } // previous file is compressed in a cabinet (and not modified above) if (null != objectField.PreviousCabinetFileId && isPreviousDefault) { // index cabinets that have not been previously encountered if (!cabinets.ContainsKey(objectField.PreviousBaseUri)) { Uri baseUri = new Uri(objectField.PreviousBaseUri); string localFileNameWithoutExtension = Path.GetFileNameWithoutExtension(baseUri.LocalPath); string extractedDirectoryName = String.Format(CultureInfo.InvariantCulture, "cab_{0}_{1}", cabinets.Count, localFileNameWithoutExtension); // index the cabinet file's base URI (source location) and extracted directory cabinets.Add(objectField.PreviousBaseUri, Path.Combine(tempFilesLocation, extractedDirectoryName)); } // set the path to the file once its extracted from the cabinet previousFile = Path.Combine((string)cabinets[objectField.PreviousBaseUri], objectField.PreviousCabinetFileId); } else if (null != objectField.PreviousData && null != binderFileManager) { previousFile = binderFileManager.ResolveFile((string)objectField.PreviousData, table.Name, row.SourceLineNumbers, BindStage.Normal); } // add the file to the list of files to go in the cabinet if (null != previousFile) { string cabinetFileId = (index++).ToString(CultureInfo.InvariantCulture); objectField.PreviousCabinetFileId = cabinetFileId; fileIds.Add(cabinetFileId); files.Add(previousFile); } } } } } }
/// <summary> /// Saves an outputs cab to a path on disk. /// </summary> /// <param name="path">Path to save outputs cab to on disk.</param> /// <param name="binderFileManager">If provided, the binder file manager is used to bind files into the outputs cab.</param> /// <param name="wixVariableResolver">The Wix variable resolver.</param> /// <param name="tempFilesLocation">Location for temporary files.</param> /// <returns>Returns true if a cabinet existed or was created, false otherwise.</returns> public bool SaveCab(string path, BinderFileManager binderFileManager, WixVariableResolver wixVariableResolver, string tempFilesLocation) { bool hasCab = false; // Check if there was a cab on the wixout when it was created if (null != this.cabPath) { // There was already a cab on the wixout when it was loaded. Reuse that one. File.Copy(this.cabPath, path, true); if (null != this.tempFileCollection) { this.tempFileCollection.Delete(); } hasCab = true; } else { int index = 0; Hashtable cabinets = new Hashtable(); StringCollection fileIds = new StringCollection(); StringCollection files = new StringCollection(); if (null != tempFilesLocation) { // resolve paths to files and create the output cabinet file if (0 == this.sections.Count) { Output.ResolveSectionFiles(this.tables, binderFileManager, wixVariableResolver, tempFilesLocation, cabinets, fileIds, files, ref index); } else { foreach (Section section in this.sections) { Output.ResolveSectionFiles(section.Tables, binderFileManager, wixVariableResolver, tempFilesLocation, cabinets, fileIds, files, ref index); } } } // extract files that come from cabinet files if (0 < cabinets.Count) { // ensure the temporary directory exists Directory.CreateDirectory(tempFilesLocation); foreach (DictionaryEntry cabinet in cabinets) { Uri baseUri = new Uri((string)cabinet.Key); string localPath; if ("embeddedresource" == baseUri.Scheme) { int bytesRead; byte[] buffer = new byte[512]; string originalLocalPath = Path.GetFullPath(baseUri.LocalPath.Substring(1)); string resourceName = baseUri.Fragment.Substring(1); Assembly assembly = Assembly.LoadFile(originalLocalPath); localPath = String.Concat(cabinet.Value, ".cab"); using (FileStream fs = File.OpenWrite(localPath)) { using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName)) { while (0 < (bytesRead = resourceStream.Read(buffer, 0, buffer.Length))) { fs.Write(buffer, 0, bytesRead); } } } } else // normal file { localPath = baseUri.LocalPath; } // extract the cabinet's files into a temporary directory Directory.CreateDirectory((string)cabinet.Value); using (WixExtractCab extractCab = new WixExtractCab()) { extractCab.Extract(localPath, (string)cabinet.Value); } } } // create the cabinet file if (0 < fileIds.Count) { using (WixCreateCab cab = new WixCreateCab(Path.GetFileName(path), Path.GetDirectoryName(path), fileIds.Count, 0, 0, CompressionLevel.Mszip)) { for (int i = 0; i < fileIds.Count; i++) { cab.AddFile(files[i], fileIds[i]); } cab.Complete(); } // append the output xml to the end of the newly created cabinet file hasCab = true; } } return hasCab; }
/// <summary> /// Saves an outputs cab to a path on disk. /// </summary> /// <param name="path">Path to save outputs cab to on disk.</param> /// <param name="binderFileManager">If provided, the binder file manager is used to bind files into the outputs cab.</param> /// <param name="wixVariableResolver">The Wix variable resolver.</param> /// <param name="tempFilesLocation">Location for temporary files.</param> /// <returns>Returns true if a cabinet existed or was created, false otherwise.</returns> public bool SaveCab(string path, BinderFileManager binderFileManager, WixVariableResolver wixVariableResolver, string tempFilesLocation) { bool hasCab = false; // Check if there was a cab on the wixout when it was created if (null != this.cabPath) { // There was already a cab on the wixout when it was loaded. Reuse that one. File.Copy(this.cabPath, path, true); if (null != this.tempFileCollection) { this.tempFileCollection.Delete(); } hasCab = true; } else { int index = 0; Hashtable cabinets = new Hashtable(); StringCollection fileIds = new StringCollection(); StringCollection files = new StringCollection(); if (null != tempFilesLocation) { // resolve paths to files and create the output cabinet file if (0 == this.sections.Count) { Output.ResolveSectionFiles(this.tables, binderFileManager, wixVariableResolver, tempFilesLocation, cabinets, fileIds, files, ref index); } else { foreach (Section section in this.sections) { Output.ResolveSectionFiles(section.Tables, binderFileManager, wixVariableResolver, tempFilesLocation, cabinets, fileIds, files, ref index); } } } // extract files that come from cabinet files if (0 < cabinets.Count) { // ensure the temporary directory exists Directory.CreateDirectory(tempFilesLocation); foreach (DictionaryEntry cabinet in cabinets) { Uri baseUri = new Uri((string)cabinet.Key); string localPath; if ("embeddedresource" == baseUri.Scheme) { int bytesRead; byte[] buffer = new byte[512]; string originalLocalPath = Path.GetFullPath(baseUri.LocalPath.Substring(1)); string resourceName = baseUri.Fragment.Substring(1); Assembly assembly = Assembly.LoadFile(originalLocalPath); localPath = String.Concat(cabinet.Value, ".cab"); using (FileStream fs = File.OpenWrite(localPath)) { using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName)) { while (0 < (bytesRead = resourceStream.Read(buffer, 0, buffer.Length))) { fs.Write(buffer, 0, bytesRead); } } } } else // normal file { localPath = baseUri.LocalPath; } // extract the cabinet's files into a temporary directory Directory.CreateDirectory((string)cabinet.Value); using (WixExtractCab extractCab = new WixExtractCab()) { extractCab.Extract(localPath, (string)cabinet.Value); } } } // create the cabinet file if (0 < fileIds.Count) { using (WixCreateCab cab = new WixCreateCab(Path.GetFileName(path), Path.GetDirectoryName(path), fileIds.Count, 0, 0, CompressionLevel.Mszip)) { for (int i = 0; i < fileIds.Count; i++) { cab.AddFile(files[i], fileIds[i]); } cab.Complete(); } // append the output xml to the end of the newly created cabinet file hasCab = true; } } return(hasCab); }