/// <summary> /// Genereate localized baml /// </summary> private static void GenerateBamlResources(LocBamlOptions options) { Stream input = File.OpenRead(options.Translations); using (ResourceTextReader reader = new ResourceTextReader(options.TranslationFileType, input)) { TranslationDictionariesReader dictionaries = new TranslationDictionariesReader(reader); ResourceGenerator.Generate(options, dictionaries); } }
public static string GenerateBamlResourcesFromStream(LocBamlOptions options, Stream stream) { string errors; using (ResourceTextReader reader = new ResourceTextReader(options.TranslationFileType, stream)) { TranslationDictionariesReader dictionaries = new TranslationDictionariesReader(reader); errors = ResourceGenerator.Generate(options, dictionaries); } return(errors); }
/// <summary> /// Genereate localized baml /// </summary> private static void GenerateBamlResources(LocBamlOptions options) { Stream input = File.OpenRead(options.Translations); using (ResourceTextReader reader = new ResourceTextReader(options.TranslationFileType, input)) { TranslationDictionariesReader dictionaries = new TranslationDictionariesReader(reader); ResourceGenerator.Generate(options, dictionaries); } }
/// <summary> /// Generates localized Baml from translations /// </summary> /// <param name="options">LocBaml options</param> /// <param name="dictionaries">the translation dictionaries</param> internal static void Generate(LocBamlOptions options, TranslationDictionariesReader dictionaries) { // base on the input, we generate differently switch(options.InputType) { case FileType.BAML : { // input file name string bamlName = Path.GetFileName(options.Input); // outpuf file name is Output dir + input file name string outputFileName = GetOutputFileName(options); // construct the full path string fullPathOutput = Path.Combine(options.Output, outputFileName); options.Write(StringLoader.Get("GenerateBaml", fullPathOutput)); using (Stream input = File.OpenRead(options.Input)) { using (Stream output = new FileStream(fullPathOutput, FileMode.Create)) { BamlLocalizationDictionary dictionary = dictionaries[bamlName]; // if it is null, just create an empty dictionary. if (dictionary == null) dictionary = new BamlLocalizationDictionary(); GenerateBamlStream(input, output, dictionary, options); } } options.WriteLine(StringLoader.Get("Done")); break; } case FileType.RESOURCES : { string outputFileName = GetOutputFileName(options); string fullPathOutput = Path.Combine(options.Output, outputFileName); using (Stream input = File.OpenRead(options.Input)) { using (Stream output = File.OpenWrite(fullPathOutput)) { // create a Resource reader on the input; IResourceReader reader = new ResourceReader(input); // create a writer on the output; IResourceWriter writer = new ResourceWriter(output); GenerateResourceStream( options, // options options.Input, // resources name reader, // resource reader writer, // resource writer dictionaries); // translations reader.Close(); // now generate and close writer.Generate(); writer.Close(); } } options.WriteLine(StringLoader.Get("DoneGeneratingResource", outputFileName)); break; } case FileType.EXE: case FileType.DLL: { GenerateAssembly(options, dictionaries); break; } default: { Debug.Assert(false, "Can't generate to this type"); break; } } }
private static void GenerateResourceStream( LocBamlOptions options, // options from the command line string resourceName, // the name of the .resources file IResourceReader reader, // the reader for the .resources IResourceWriter writer, // the writer for the output .resources TranslationDictionariesReader dictionaries // the translations ) { options.WriteLine(StringLoader.Get("GenerateResource", resourceName)); // enumerate through each resource and generate it foreach(DictionaryEntry entry in reader) { string name = entry.Key as string; object resourceValue = null; // See if it looks like a Baml resource if (BamlStream.IsResourceEntryBamlStream(name, entry.Value)) { Stream targetStream = null; options.Write(" "); options.Write(StringLoader.Get("GenerateBaml", name)); // grab the localizations available for this Baml string bamlName = BamlStream.CombineBamlStreamName(resourceName, name); BamlLocalizationDictionary localizations = dictionaries[bamlName]; if (localizations != null) { targetStream = new MemoryStream(); // generate into a new Baml stream GenerateBamlStream( (Stream) entry.Value, targetStream, localizations, options ); } options.WriteLine(StringLoader.Get("Done")); // sets the generated object to be the generated baml stream resourceValue = targetStream; } if (resourceValue == null) { // // The stream is not localized as Baml yet, so we will make a copy of this item into // the localized resources // // We will add the value as is if it is serializable. Otherwise, make a copy resourceValue = entry.Value; object[] serializableAttributes = resourceValue.GetType().GetCustomAttributes(typeof(SerializableAttribute), true); if (serializableAttributes.Length == 0) { // The item returned from resource reader is not serializable // If it is Stream, we can wrap all the values in a MemoryStream and // add to the resource. Otherwise, we had to skip this resource. Stream resourceStream = resourceValue as Stream; if (resourceStream != null) { Stream targetStream = new MemoryStream(); byte[] buffer = new byte[resourceStream.Length]; resourceStream.Read(buffer, 0, buffer.Length); targetStream = new MemoryStream(buffer); resourceValue = targetStream; } } } if (resourceValue != null) { writer.AddResource(name, resourceValue); } } }
//-------------------------------------------------- // The function follows Managed code parser // implementation. in the future, maybe they should // share the same code //-------------------------------------------------- private static void GenerateAssembly(LocBamlOptions options, TranslationDictionariesReader dictionaries) { // there are many names to be used when generating an assembly string sourceAssemblyFullName = options.Input; // source assembly full path string outputAssemblyDir = options.Output; // output assembly directory string outputAssemblyLocalName = GetOutputFileName(options); // output assembly name string moduleLocalName = GetAssemblyModuleLocalName(options, outputAssemblyLocalName); // the module name within the assmbly // get the source assembly Assembly srcAsm = Assembly.LoadFrom(sourceAssemblyFullName); // obtain the assembly name AssemblyName targetAssemblyNameObj = srcAsm.GetName(); // store the culture info of the source assembly CultureInfo srcCultureInfo = targetAssemblyNameObj.CultureInfo; // update it to use it for target assembly targetAssemblyNameObj.Name = Path.GetFileNameWithoutExtension(outputAssemblyLocalName); targetAssemblyNameObj.CultureInfo = options.CultureInfo; // we get a assembly builder AssemblyBuilder targetAssemblyBuilder = Thread.GetDomain().DefineDynamicAssembly( targetAssemblyNameObj, // name of the assembly AssemblyBuilderAccess.RunAndSave, // access rights outputAssemblyDir // storage dir ); // we create a module builder for embeded resource modules ModuleBuilder moduleBuilder = targetAssemblyBuilder.DefineDynamicModule( moduleLocalName, outputAssemblyLocalName ); options.WriteLine(StringLoader.Get("GenerateAssembly")); // now for each resource in the assembly foreach (string resourceName in srcAsm.GetManifestResourceNames()) { // get the resource location for the resource ResourceLocation resourceLocation = srcAsm.GetManifestResourceInfo(resourceName).ResourceLocation; // if this resource is in another assemlby, we will skip it if ((resourceLocation & ResourceLocation.ContainedInAnotherAssembly) != 0) { continue; // in resource assembly, we don't have resource that is contained in another assembly } // gets the neutral resource name, giving it the source culture info string neutralResourceName = GetNeutralResModuleName(resourceName, srcCultureInfo); // gets the target resource name, by giving it the target culture info string targetResourceName = GetCultureSpecificResourceName(neutralResourceName, options.CultureInfo); // resource stream Stream resourceStream = srcAsm.GetManifestResourceStream(resourceName); // see if it is a .resources if (neutralResourceName.ToLower(CultureInfo.InvariantCulture).EndsWith(".resources")) { // now we think we have resource stream // get the resource writer IResourceWriter writer; // check if it is a embeded assembly if ((resourceLocation & ResourceLocation.Embedded) != 0) { // gets the resource writer from the module builder writer = moduleBuilder.DefineResource( targetResourceName, // resource name targetResourceName, // resource description ResourceAttributes.Public // visibilty of this resource to other assembly ); } else { // it is a standalone resource, we get the resource writer from the assembly builder writer = targetAssemblyBuilder.DefineResource( targetResourceName, // resource name targetResourceName, // description targetResourceName, // file name to save to ResourceAttributes.Public // visibility of this resource to other assembly ); } // get the resource reader IResourceReader reader = new ResourceReader(resourceStream); // generate the resources GenerateResourceStream(options, resourceName, reader, writer, dictionaries); // we don't call writer.Generate() or writer.Close() here // because the AssemblyBuilder will call them when we call Save() on it. } else { // else it is a stand alone untyped manifest resources. string extension = Path.GetExtension(targetResourceName); string fullFileName = Path.Combine(outputAssemblyDir, targetResourceName); // check if it is a .baml, case-insensitive if (string.Compare(extension, ".baml", true, CultureInfo.InvariantCulture) == 0) { // try to localized the the baml // find the resource dictionary BamlLocalizationDictionary dictionary = dictionaries[resourceName]; // if it is null, just create an empty dictionary. if (dictionary != null) { // it is a baml stream using (Stream output = File.OpenWrite(fullFileName)) { options.Write(" "); options.WriteLine(StringLoader.Get("GenerateStandaloneBaml", fullFileName)); GenerateBamlStream(resourceStream, output, dictionary, options); options.WriteLine(StringLoader.Get("Done")); } } else { // can't find localization of it, just copy it GenerateStandaloneResource( fullFileName, resourceStream); } } else { // it is an untyped resource stream, just copy it GenerateStandaloneResource( fullFileName, resourceStream); } // now add this resource file into the assembly targetAssemblyBuilder.AddResourceFile( targetResourceName, // resource name targetResourceName, // file name ResourceAttributes.Public // visibility of the resource to other assembly ); } } // at the end, generate the assembly targetAssemblyBuilder.Save(outputAssemblyLocalName); options.WriteLine(StringLoader.Get("DoneGeneratingAssembly")); }
/// <summary> /// Generates localized Baml from translations /// </summary> /// <param name="options">LocBaml options</param> /// <param name="dictionaries">the translation dictionaries</param> internal static string Generate(LocBamlOptions options, TranslationDictionariesReader dictionaries) { // base on the input, we generate differently switch (options.InputType) { case FileType.BAML: { // input file name string bamlName = Path.GetFileName(options.Input); // output file name is output dir + input file name string outputFileName = GetOutputFileName(options); // construct the full path string fullPathOutput = Path.Combine(options.Output, outputFileName); options.Write(StringLoader.Get("GenerateBaml", fullPathOutput)); using (Stream input = File.OpenRead(options.Input)) { using (Stream output = new FileStream(fullPathOutput, FileMode.Create)) { BamlLocalizationDictionary dictionary = dictionaries[bamlName]; // if it is null, just create an empty dictionary. if (dictionary == null) { dictionary = new BamlLocalizationDictionary(); } string status = GenerateBamlStream(input, output, dictionary, options); if (status != null) { return(status); } } } options.WriteLine(StringLoader.Get("Done")); break; } case FileType.RESOURCES: { string outputFileName = GetOutputFileName(options); string fullPathOutput = Path.Combine(options.Output, outputFileName); using (Stream input = File.OpenRead(options.Input)) { using (Stream output = File.OpenWrite(fullPathOutput)) { // create a Resource reader on the input; IResourceReader reader = new ResourceReader(input); // create a writer on the output; IResourceWriter writer = new ResourceWriter(output); string status = GenerateResourceStream( options, // options options.Input, // resources name reader, // resource reader writer, // resource writer dictionaries); // translations reader.Close(); if (status != null) { return(status); } // now generate and close writer.Generate(); writer.Close(); } } options.WriteLine(StringLoader.Get("DoneGeneratingResource", outputFileName)); break; } case FileType.EXE: case FileType.DLL: { string status = GenerateAssembly(options, dictionaries); if (status != null) { return(status); } break; } default: { Debug.Assert(false, "Can't generate to this type"); return("Can't generate to a resource of the type EXE"); break; } } return(null); }
//-------------------------------------------------- // The function follows Managed code parser // implementation. in the future, maybe they should // share the same code //-------------------------------------------------- private static string GenerateAssembly(LocBamlOptions options, TranslationDictionariesReader dictionaries) { // there are many names to be used when generating an assembly string sourceAssemblyFullName = options.Input; // source assembly full path string outputAssemblyDir = options.Output; // output assembly directory string outputAssemblyLocalName = GetOutputFileName(options); // output assembly name string moduleLocalName = GetAssemblyModuleLocalName(options, outputAssemblyLocalName); // the module name within the assembly // get the source assembly Assembly srcAsm = Assembly.LoadFrom(sourceAssemblyFullName); // obtain the assembly name AssemblyName targetAssemblyNameObj = srcAsm.GetName(); // store the culture info of the source assembly CultureInfo srcCultureInfo = targetAssemblyNameObj.CultureInfo; // update it to use it for target assembly targetAssemblyNameObj.Name = Path.GetFileNameWithoutExtension(outputAssemblyLocalName); targetAssemblyNameObj.CultureInfo = options.CultureInfo; // we get a assembly builder AssemblyBuilder targetAssemblyBuilder = Thread.GetDomain().DefineDynamicAssembly( targetAssemblyNameObj, // name of the assembly AssemblyBuilderAccess.RunAndSave, // access rights outputAssemblyDir // storage dir ); // we create a module builder for embedded resource modules ModuleBuilder moduleBuilder = targetAssemblyBuilder.DefineDynamicModule( moduleLocalName, outputAssemblyLocalName ); options.WriteLine(StringLoader.Get("GenerateAssembly")); // now for each resource in the assembly foreach (string resourceName in srcAsm.GetManifestResourceNames()) { // get the resource location for the resource ResourceLocation resourceLocation = srcAsm.GetManifestResourceInfo(resourceName).ResourceLocation; // if this resource is in another assembly, we will skip it if ((resourceLocation & ResourceLocation.ContainedInAnotherAssembly) != 0) { continue; // in resource assembly, we don't have resource that is contained in another assembly } // gets the neutral resource name, giving it the source culture info string neutralResourceName = GetNeutralResModuleName(resourceName, srcCultureInfo); // gets the target resource name, by giving it the target culture info string targetResourceName = GetCultureSpecificResourceName(neutralResourceName, options.CultureInfo); // resource stream Stream resourceStream = srcAsm.GetManifestResourceStream(resourceName); // see if it is a .resources if (neutralResourceName.ToLower(CultureInfo.InvariantCulture).EndsWith(".resources")) { // now we think we have resource stream // get the resource writer IResourceWriter writer; // check if it is a embedded assembly if ((resourceLocation & ResourceLocation.Embedded) != 0) { // gets the resource writer from the module builder writer = moduleBuilder.DefineResource( targetResourceName, // resource name targetResourceName, // resource description ResourceAttributes.Public // visibility of this resource to other assembly ); } else { // it is a standalone resource, we get the resource writer from the assembly builder writer = targetAssemblyBuilder.DefineResource( targetResourceName, // resource name targetResourceName, // description targetResourceName, // file name to save to ResourceAttributes.Public // visibility of this resource to other assembly ); } // get the resource reader IResourceReader reader = new ResourceReader(resourceStream); // generate the resources string status = GenerateResourceStream(options, resourceName, reader, writer, dictionaries); if (status != null) { return(status); } // we don't call writer.Generate() or writer.Close() here // because the AssemblyBuilder will call them when we call Save() on it. } else { // else it is a stand alone untyped manifest resources. string extension = Path.GetExtension(targetResourceName); string fullFileName = Path.Combine(outputAssemblyDir, targetResourceName); // check if it is a .baml, case-insensitive if (string.Compare(extension, ".baml", true, CultureInfo.InvariantCulture) == 0) { // try to localized the baml // find the resource dictionary BamlLocalizationDictionary dictionary = dictionaries[resourceName]; // if it is null, just create an empty dictionary. if (dictionary != null) { // it is a baml stream using (Stream output = File.OpenWrite(fullFileName)) { options.Write(" "); options.WriteLine(StringLoader.Get("GenerateStandaloneBaml", fullFileName)); GenerateBamlStream(resourceStream, output, dictionary, options); options.WriteLine(StringLoader.Get("Done")); } } else { // can't find localization of it, just copy it GenerateStandaloneResource(fullFileName, resourceStream); } } else { // it is an untyped resource stream, just copy it GenerateStandaloneResource(fullFileName, resourceStream); } // now add this resource file into the assembly targetAssemblyBuilder.AddResourceFile( targetResourceName, // resource name targetResourceName, // file name ResourceAttributes.Public // visibility of the resource to other assembly ); } } // at the end, generate the assembly targetAssemblyBuilder.Save(outputAssemblyLocalName); options.WriteLine(StringLoader.Get("DoneGeneratingAssembly")); return(null); }
private static string GenerateResourceStream( LocBamlOptions options, // options from the command line string resourceName, // the name of the .resources file IResourceReader reader, // the reader for the .resources IResourceWriter writer, // the writer for the output .resources TranslationDictionariesReader dictionaries // the translations ) { options.WriteLine(StringLoader.Get("GenerateResource", resourceName)); // enumerate through each resource and generate it foreach (DictionaryEntry entry in reader) { string name = entry.Key as string; object resourceValue = null; // See if it looks like a Baml resource if (BamlStream.IsResourceEntryBamlStream(name, entry.Value)) { Stream targetStream = null; options.Write(" "); options.Write(StringLoader.Get("GenerateBaml", name)); // grab the localizations available for this Baml string bamlName = BamlStream.CombineBamlStreamName(resourceName, name); BamlLocalizationDictionary localizations = dictionaries[bamlName]; if (localizations != null) { targetStream = new MemoryStream(); // generate into a new Baml stream string status = GenerateBamlStream( (Stream)entry.Value, targetStream, localizations, options ); if (status != null) { options.WriteLine(status); return(status); } } options.WriteLine(StringLoader.Get("Done")); // sets the generated object to be the generated baml stream resourceValue = targetStream; } if (resourceValue == null) { // // The stream is not localized as Baml yet, so we will make a copy of this item into // the localized resources // // We will add the value as is if it is serializable. Otherwise, make a copy resourceValue = entry.Value; object[] serializableAttributes = resourceValue.GetType().GetCustomAttributes(typeof(SerializableAttribute), true); if (serializableAttributes.Length == 0) { // The item returned from resource reader is not serializable // If it is Stream, we can wrap all the values in a MemoryStream and // add to the resource. Otherwise, we had to skip this resource. Stream resourceStream = resourceValue as Stream; if (resourceStream != null) { Stream targetStream = new MemoryStream(); byte[] buffer = new byte[resourceStream.Length]; resourceStream.Read(buffer, 0, buffer.Length); targetStream = new MemoryStream(buffer); resourceValue = targetStream; } } } if (resourceValue != null) { writer.AddResource(name, resourceValue); } } return(null); }
public override bool Execute() { _Options = new LocBamlOptions(); _Options.CultureInfo = new CultureInfo(Culture); // generation-related options _Options.ToGenerate = true; _Options.Translations = TranslationsFile; _Options.Input = InputFile; _Options.Output = OutputFolder; // TBD: Should we do this automatically or not? if (!System.IO.Directory.Exists(OutputFolder)) { System.IO.Directory.CreateDirectory(OutputFolder); } _Options.ToParse = false; // Just to get rid of compiler warnings _Options.HasNoLogo = true; // TODO: if ((Assemblies == null) || (Assemblies.Length == 0)) { _Options.AssemblyPaths = null; } else { _Options.AssemblyPaths = new System.Collections.ArrayList(); _Options.AssemblyPaths.AddRange(Assemblies); } AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; // TODO: Add a logger interface so we can use MSBuild logger from // LocBamlOptions.Write() and WriteLine() _Options.IsVerbose = true; bool success = true; string errorString = _Options.CheckAndSetDefault(); if (errorString != null) { Log.LogError(errorString); success = false; } else { try { TranslationDictionariesReader dictionaries = _Options.GetTranslationsDictionary(); ResourceGenerator.Generate(_Options, dictionaries); } catch (Exception e) { Log.LogError("Exception generating: {0}", e.Message); success = false; } Log.LogMessage("Done with LocBamlGenerate"); } AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve; return(success); }
/// <summary> /// Genereate localized baml /// </summary> private static void GenerateBamlResources(LocBamlOptions options) { TranslationDictionariesReader dictionaries = options.GetTranslationsDictionary(); ResourceGenerator.Generate(options, dictionaries); }
public override bool Execute() { // First stage: parse _Options = new LocBamlOptions(); _Options.ToParse = true; _Options.Input = InputFile; _Options.Output = TranslationsFile; _Options.CultureInfo = new CultureInfo(Culture); // Just to get rid of compiler warnings _Options.HasNoLogo = true; // generation-related options _Options.ToGenerate = false; _Options.Translations = string.Empty; // TODO: if ((Assemblies == null) || (Assemblies.Length == 0)) { _Options.AssemblyPaths = null; } else { _Options.AssemblyPaths = new System.Collections.ArrayList(); _Options.AssemblyPaths.AddRange(Assemblies); } AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; // TODO: Add a logger interface so we can use MSBuild logger from // LocBamlOptions.Write() and WriteLine() _Options.IsVerbose = true; bool success = true; string errorString = _Options.CheckAndSetDefault(); if (errorString != null) { Log.LogError(errorString); AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve; success = false; } else { try { TranslationDictionariesWriter.Write(_Options); } catch (Exception e) { Log.LogError("Exception parsing: {0}", e.Message); success = false; } } // TBD: a way to override automatic algorithm? string outputFolder = Path.GetDirectoryName(Path.GetFullPath(InputFile)); string[] folderParts = outputFolder.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); // Try to figure out if the ouptut folder is a culture name, if so remove it foreach (CultureInfo culture in CultureInfo.GetCultures(CultureTypes.AllCultures)) { string cName = culture.Name; if (string.IsNullOrEmpty(cName)) { continue; } if (folderParts[folderParts.Length - 1].Equals(cName, StringComparison.InvariantCultureIgnoreCase)) { outputFolder = string.Join(Path.DirectorySeparatorChar.ToString(), folderParts, 0, folderParts.Length - 1); outputFolder = Path.Combine(outputFolder, _Options.CultureInfo.Name); break; } } if (success) { // Don't call _Options.CheckAndSetDefault() again because it will reload the assemblies // generation-related options _Options.ToGenerate = true; _Options.Translations = TranslationsFile; _Options.Input = InputFile; _Options.Output = outputFolder; // TBD: Should we do this automatically or not? if (!Directory.Exists(outputFolder)) { Directory.CreateDirectory(outputFolder); } _Options.ToParse = false; try { TranslationDictionariesReader dictionaries = _Options.GetTranslationsDictionary(); ResourceGenerator.Generate(_Options, dictionaries); } catch (Exception e) { Log.LogError("Exception generating: {0}", e.Message); success = false; } } // Cleanup AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve; return(success); }
//-------------------------------------------------- // The function follows Managed code parser // implementation. in the future, maybe they should // share the same code //-------------------------------------------------- private static void GenerateAssembly(LocBamlOptions options, TranslationDictionariesReader dictionaries) { // there are many names to be used when generating an assembly string sourceAssemblyFullName = options.Input; // source assembly full path string outputAssemblyDir = options.Output; // output assembly directory string outputAssemblyLocalName = GetOutputFileName(options); // output assembly name string moduleLocalName = GetAssemblyModuleLocalName(options, outputAssemblyLocalName); // the module name within the assmbly // get the source assembly byte[] sourceContents = File.ReadAllBytes(sourceAssemblyFullName); Assembly srcAsm = Assembly.Load(sourceContents); // obtain the assembly name AssemblyName targetAssemblyNameObj = srcAsm.GetName(); // store the culture info of the source assembly CultureInfo srcCultureInfo = targetAssemblyNameObj.CultureInfo; // update it to use it for target assembly targetAssemblyNameObj.Name = Path.GetFileNameWithoutExtension(outputAssemblyLocalName); targetAssemblyNameObj.CultureInfo = options.CultureInfo; // we get a assembly builder AssemblyBuilder targetAssemblyBuilder = Thread.GetDomain().DefineDynamicAssembly( targetAssemblyNameObj, // name of the assembly AssemblyBuilderAccess.RunAndSave, // access rights outputAssemblyDir // storage dir ); // we create a module builder for embeded resource modules ModuleBuilder moduleBuilder = targetAssemblyBuilder.DefineDynamicModule( moduleLocalName, outputAssemblyLocalName ); Dictionary <string, IResourceWriter> resourceWriters = new Dictionary <string, IResourceWriter>(); // If the output assembly already exists, copy the embedded resources to the new assembly string existingAssemblyName = Path.Combine(Directory.GetCurrentDirectory(), options.CultureInfo.Name, outputAssemblyLocalName); if (File.Exists(existingAssemblyName)) { // Use ReadAllBytes() so we don't hold a file handle open, which would prevent // us from overwriting the file at the end. Assembly existingAssembly = Assembly.Load(File.ReadAllBytes(existingAssemblyName)); string[] existingResourceNames = existingAssembly.GetManifestResourceNames(); foreach (string resourceName in existingResourceNames) { ManifestResourceInfo info = existingAssembly.GetManifestResourceInfo(resourceName); if ((info.ResourceLocation & ResourceLocation.Embedded) != ResourceLocation.Embedded) { continue; } IResourceWriter writer; if (!resourceWriters.TryGetValue(resourceName, out writer)) { writer = moduleBuilder.DefineResource( resourceName, // resource name resourceName, // resource description ResourceAttributes.Public // visibilty of this resource to other assembly ); resourceWriters.Add(resourceName, writer); } Stream resourceStream = existingAssembly.GetManifestResourceStream(resourceName); using (ResourceReader reader = new ResourceReader(resourceStream)) { foreach (DictionaryEntry entry in reader) { string key = entry.Key.ToString(); object value = entry.Value; if (key.EndsWith(".baml")) { // Skip it, we're going to get this from the untranslated assembly continue; } writer.AddResource(key, value); } } } } // Add assembly info, trying to preserver original values as close as possible CopyAssemblyVersion(targetAssemblyBuilder, srcAsm); options.WriteLine(StringLoader.Get("GenerateAssembly")); // now for each resource in the assembly foreach (string resourceName in srcAsm.GetManifestResourceNames()) { // get the resource location for the resource ResourceLocation resourceLocation = srcAsm.GetManifestResourceInfo(resourceName).ResourceLocation; // if this resource is in another assemlby, we will skip it if ((resourceLocation & ResourceLocation.ContainedInAnotherAssembly) != 0) { continue; // in resource assembly, we don't have resource that is contained in another assembly } // gets the neutral resource name, giving it the source culture info string neutralResourceName = GetNeutralResModuleName(resourceName, srcCultureInfo); // gets the target resource name, by giving it the target culture info string targetResourceName = GetCultureSpecificResourceName(neutralResourceName, options.CultureInfo); // resource stream Stream resourceStream = srcAsm.GetManifestResourceStream(resourceName); // see if it is a .resources if (neutralResourceName.ToLower(CultureInfo.InvariantCulture).EndsWith(".resources")) { // now we think we have resource stream // get the resource writer IResourceWriter writer; // check if it is a embeded assembly if (!resourceWriters.TryGetValue(targetResourceName, out writer)) { if ((resourceLocation & ResourceLocation.Embedded) != 0) { // gets the resource writer from the module builder writer = moduleBuilder.DefineResource( targetResourceName, // resource name targetResourceName, // resource description ResourceAttributes.Public // visibilty of this resource to other assembly ); } else { // it is a standalone resource, we get the resource writer from the assembly builder writer = targetAssemblyBuilder.DefineResource( targetResourceName, // resource name targetResourceName, // description targetResourceName, // file name to save to ResourceAttributes.Public // visibility of this resource to other assembly ); } resourceWriters.Add(targetResourceName, writer); } // get the resource reader IResourceReader reader = new ResourceReader(resourceStream); // generate the resources GenerateResourceStream(options, resourceName, reader, writer, dictionaries); // we don't call writer.Generate() or writer.Close() here // because the AssemblyBuilder will call them when we call Save() on it. } else { // else it is a stand alone untyped manifest resources. string extension = Path.GetExtension(targetResourceName); string fullFileName = Path.Combine(outputAssemblyDir, targetResourceName); // check if it is a .baml, case-insensitive if (string.Compare(extension, ".baml", true, CultureInfo.InvariantCulture) == 0) { // try to localized the the baml // find the resource dictionary BamlLocalizationDictionary dictionary = dictionaries[resourceName]; // if it is null, just create an empty dictionary. if (dictionary != null) { // it is a baml stream using (Stream output = File.OpenWrite(fullFileName)) { options.Write(" "); options.WriteLine(StringLoader.Get("GenerateStandaloneBaml", fullFileName)); GenerateBamlStream(resourceStream, output, dictionary, options); options.WriteLine(StringLoader.Get("Done")); } } else { // can't find localization of it, just copy it GenerateStandaloneResource(fullFileName, resourceStream); } } else { // it is an untyped resource stream, just copy it GenerateStandaloneResource(fullFileName, resourceStream); } // now add this resource file into the assembly targetAssemblyBuilder.AddResourceFile( targetResourceName, // resource name targetResourceName, // file name ResourceAttributes.Public // visibility of the resource to other assembly ); } } // at the end, generate the assembly targetAssemblyBuilder.Save(outputAssemblyLocalName); options.WriteLine(StringLoader.Get("DoneGeneratingAssembly")); }
//-------------------------------------------------- // The function follows Managed code parser // implementation. in the future, maybe they should // share the same code //-------------------------------------------------- private static void GenerateAssembly(LocBamlOptions options, TranslationDictionariesReader dictionaries) { // there are many names to be used when generating an assembly string sourceAssemblyFullName = options.Input; // source assembly full path string outputAssemblyDir = options.Output; // output assembly directory string outputAssemblyLocalName = GetOutputFileName(options); // output assembly name string moduleLocalName = GetAssemblyModuleLocalName(options, outputAssemblyLocalName); // the module name within the assmbly // get the source assembly Assembly srcAsm = Assembly.LoadFrom(sourceAssemblyFullName); // obtain the assembly name AssemblyName targetAssemblyNameObj = srcAsm.GetName(); // store the culture info of the source assembly CultureInfo srcCultureInfo = targetAssemblyNameObj.CultureInfo; // update it to use it for target assembly targetAssemblyNameObj.Name = Path.GetFileNameWithoutExtension(outputAssemblyLocalName); targetAssemblyNameObj.CultureInfo = options.CultureInfo; // we get a assembly builder AssemblyBuilder targetAssemblyBuilder = Thread.GetDomain().DefineDynamicAssembly( targetAssemblyNameObj, // name of the assembly AssemblyBuilderAccess.RunAndSave, // access rights outputAssemblyDir // storage dir ); // Add assembly info, trying to preserver original values as close as possible Action <Type, string> AddCustomStringAttribute = (Type type, string content) => { if (string.IsNullOrEmpty(content)) { return; } ConstructorInfo ctor = type.GetConstructor(new Type[] { typeof(string) }); targetAssemblyBuilder.SetCustomAttribute(new CustomAttributeBuilder(ctor, new object[] { content })); }; bool hasInformationalVersionAttr = false; object[] attrs = srcAsm.GetCustomAttributes(false); foreach (var attr in attrs) { if (attr is AssemblyCompanyAttribute cmp) { AddCustomStringAttribute(attr.GetType(), cmp.Company); continue; } if (attr is AssemblyCopyrightAttribute copy) { AddCustomStringAttribute(attr.GetType(), copy.Copyright); continue; } if (attr is AssemblyDescriptionAttribute da) { AddCustomStringAttribute(attr.GetType(), da.Description); continue; } if (attr is AssemblyFileVersionAttribute fva) { AddCustomStringAttribute(attr.GetType(), fva.Version); if (!hasInformationalVersionAttr) { // Also set AssemblyInformationalVersionAttribute, if not set already. // The unmanaged ProductVersion is taken from that attribute. AddCustomStringAttribute(typeof(AssemblyInformationalVersionAttribute), fva.Version); } continue; } if (attr is AssemblyInformationalVersionAttribute iva) { AddCustomStringAttribute(attr.GetType(), iva.InformationalVersion); hasInformationalVersionAttr = true; continue; } if (attr is AssemblyProductAttribute pa) { AddCustomStringAttribute(attr.GetType(), pa.Product); continue; } if (attr is AssemblyTitleAttribute ta) { AddCustomStringAttribute(attr.GetType(), ta.Title); continue; } if (attr is AssemblyTrademarkAttribute tm) { AddCustomStringAttribute(attr.GetType(), tm.Trademark); continue; } if (attr is AssemblyVersionAttribute va) { AddCustomStringAttribute(attr.GetType(), va.Version); continue; } } targetAssemblyBuilder.DefineVersionInfoResource(); // we create a module builder for embeded resource modules ModuleBuilder moduleBuilder = targetAssemblyBuilder.DefineDynamicModule( moduleLocalName, outputAssemblyLocalName ); options.WriteLine(StringLoader.Get("GenerateAssembly")); // now for each resource in the assembly foreach (string resourceName in srcAsm.GetManifestResourceNames()) { // get the resource location for the resource ResourceLocation resourceLocation = srcAsm.GetManifestResourceInfo(resourceName).ResourceLocation; // if this resource is in another assemlby, we will skip it if ((resourceLocation & ResourceLocation.ContainedInAnotherAssembly) != 0) { continue; // in resource assembly, we don't have resource that is contained in another assembly } // gets the neutral resource name, giving it the source culture info string neutralResourceName = GetNeutralResModuleName(resourceName, srcCultureInfo); // gets the target resource name, by giving it the target culture info string targetResourceName = GetCultureSpecificResourceName(neutralResourceName, options.CultureInfo); // resource stream Stream resourceStream = srcAsm.GetManifestResourceStream(resourceName); // see if it is a .resources if (neutralResourceName.ToLower(CultureInfo.InvariantCulture).EndsWith(".resources")) { // now we think we have resource stream // get the resource writer IResourceWriter writer; // check if it is a embeded assembly if ((resourceLocation & ResourceLocation.Embedded) != 0) { // gets the resource writer from the module builder writer = moduleBuilder.DefineResource( targetResourceName, // resource name targetResourceName, // resource description ResourceAttributes.Public // visibilty of this resource to other assembly ); } else { // it is a standalone resource, we get the resource writer from the assembly builder writer = targetAssemblyBuilder.DefineResource( targetResourceName, // resource name targetResourceName, // description targetResourceName, // file name to save to ResourceAttributes.Public // visibility of this resource to other assembly ); } // get the resource reader IResourceReader reader = new ResourceReader(resourceStream); // generate the resources GenerateResourceStream(options, resourceName, reader, writer, dictionaries); // we don't call writer.Generate() or writer.Close() here // because the AssemblyBuilder will call them when we call Save() on it. } else { // else it is a stand alone untyped manifest resources. string extension = Path.GetExtension(targetResourceName); string fullFileName = Path.Combine(outputAssemblyDir, targetResourceName); // check if it is a .baml, case-insensitive if (string.Compare(extension, ".baml", true, CultureInfo.InvariantCulture) == 0) { // try to localized the the baml // find the resource dictionary BamlLocalizationDictionary dictionary = dictionaries[resourceName]; // if it is null, just create an empty dictionary. if (dictionary != null) { // it is a baml stream using (Stream output = File.OpenWrite(fullFileName)) { options.Write(" "); options.WriteLine(StringLoader.Get("GenerateStandaloneBaml", fullFileName)); GenerateBamlStream(resourceStream, output, dictionary, options); options.WriteLine(StringLoader.Get("Done")); } } else { // can't find localization of it, just copy it GenerateStandaloneResource(fullFileName, resourceStream); } } else { // it is an untyped resource stream, just copy it GenerateStandaloneResource(fullFileName, resourceStream); } // now add this resource file into the assembly targetAssemblyBuilder.AddResourceFile( targetResourceName, // resource name targetResourceName, // file name ResourceAttributes.Public // visibility of the resource to other assembly ); } } // at the end, generate the assembly targetAssemblyBuilder.Save(outputAssemblyLocalName); options.WriteLine(StringLoader.Get("DoneGeneratingAssembly")); }