///////////////////////////////////////////////////////////////////////////////// // Paint.NET // // Copyright (C) Rick Brewster, Tom Jackson, and past contributors. // // Portions Copyright (C) Microsoft Corporation. All Rights Reserved. // // See src/Resources/Files/License.txt for full licensing and attribution // // details. // // . // ///////////////////////////////////////////////////////////////////////////////// using PaintDotNet.SystemLayer; using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using System.Globalization; using System.IO; using System.Reflection; using System.Resources; using System.Windows.Forms; namespace PaintDotNet { public static class PdnResources { private static ResourceManager resourceManager; private const string ourNamespace = "PaintDotNet"; private static Assembly ourAssembly; private static string[] localeDirs; private static CultureInfo pdnCulture; private static string resourcesDir; public static string ResourcesDir { get { if (resourcesDir == null) { resourcesDir = Path.GetDirectoryName(typeof(PdnResources).Assembly.Location); } return resourcesDir; } set { resourcesDir = value; Initialize(); } } public static CultureInfo Culture { get { return pdnCulture; } set { System.Threading.Thread.CurrentThread.CurrentUICulture = value; Initialize(); } } private static void Initialize() { resourceManager = CreateResourceManager(); ourAssembly = Assembly.GetExecutingAssembly(); pdnCulture = CultureInfo.CurrentUICulture; localeDirs = GetLocaleDirs(); } static PdnResources() { Initialize(); } public static void SetNewCulture(IWin32Window owner, string newLocaleName) { // TODO, HACK: post-3.0 we must refactor and have an actual user data manager that can handle all this renaming string oldUserDataPath = PdnInfo.UserDataPath; string oldPaletteDirName = PdnResources.GetString("ColorPalettes.UserDataSubDirName"); // END HACK CultureInfo newCI = new CultureInfo(newLocaleName); Settings.CurrentUser.SetString("LanguageName", newLocaleName); Culture = newCI; // TODO, HACK: finish up renaming string newUserDataPath = PdnInfo.UserDataPath; string newPaletteDirName = PdnResources.GetString("ColorPalettes.UserDataSubDirName"); // 1. rename user data dir from old localized name to new localized name if (oldUserDataPath != newUserDataPath) { try { Directory.Move(oldUserDataPath, newUserDataPath); } catch (Exception) { } } // 2. rename palette dir from old localized name (in new localized user data path) to new localized name string oldPalettePath = Path.Combine(newUserDataPath, oldPaletteDirName); string newPalettePath = Path.Combine(newUserDataPath, newPaletteDirName); if (oldPalettePath != newPalettePath) { try { Directory.Move(oldPalettePath, newPalettePath); } catch (Exception) { } } // END HACK string message = PdnResources.GetString("SetLanguage.PleaseRestartApplication"); MessageBox.Show(owner, message, PdnInfo.GetBareProductName(), MessageBoxButtons.OK, MessageBoxIcon.Information); } public static string[] GetInstalledLocales() { const string left = "PaintDotNet.Strings.3"; const string right = ".resources"; string ourDir = ResourcesDir; string fileSpec = left + "*" + right; string[] pathNames = Directory.GetFiles(ourDir, fileSpec); List locales = new List(); for (int i = 0; i < pathNames.Length; ++i) { string pathName = pathNames[i]; string dirName = Path.GetDirectoryName(pathName); string fileName = Path.GetFileName(pathName); string sansRight = fileName.Substring(0, fileName.Length - right.Length); string sansLeft = sansRight.Substring(left.Length); string locale; if (sansLeft.Length > 0 && sansLeft[0] == '.') { locale = sansLeft.Substring(1); } else if (sansLeft.Length == 0) { locale = "en-US"; } else { locale = sansLeft; } try { // Ensure this locale can create a valid CultureInfo object. CultureInfo ci = new CultureInfo(locale); } catch (Exception) { // Skip past invalid locales -- don't let them crash us continue; } locales.Add(locale); } return locales.ToArray(); } public static string[] GetLocaleNameChain() { List names = new List(); CultureInfo ci = pdnCulture; while (ci.Name != string.Empty) { names.Add(ci.Name); ci = ci.Parent; } return names.ToArray(); } private static string[] GetLocaleDirs() { const string rootDirName = "Resources"; string appDir = ResourcesDir; string rootDir = Path.Combine(appDir, rootDirName); List dirs = new List(); CultureInfo ci = pdnCulture; while (ci.Name != string.Empty) { string localeDir = Path.Combine(rootDir, ci.Name); if (Directory.Exists(localeDir)) { dirs.Add(localeDir); } ci = ci.Parent; } return dirs.ToArray(); } private static ResourceManager CreateResourceManager() { const string stringsFileName = "PaintDotNet.Strings.3"; ResourceManager rm = ResourceManager.CreateFileBasedResourceManager(stringsFileName, ResourcesDir, null); return rm; } public static ResourceManager Strings { get { return resourceManager; } } public static string GetString(string stringName) { string theString = resourceManager.GetString(stringName, pdnCulture); if (theString == null) { Debug.WriteLine(stringName + " not found"); } return theString; } public static Stream GetResourceStream(string fileName) { Stream stream = null; for (int i = 0; i < localeDirs.Length; ++i) { string filePath = Path.Combine(localeDirs[i], fileName); if (File.Exists(filePath)) { stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); break; } } if (stream == null) { string fullName = ourNamespace + "." + fileName; stream = ourAssembly.GetManifestResourceStream(fullName); } return stream; } public static Image GetImageBmpOrPng(string fileNameNoExt) { // using Path.ChangeExtension is not what we want; quite often filenames are "Icons.BlahBlahBlah" string fileNameBmp = fileNameNoExt + ".bmp"; Image image = GetImage(fileNameBmp); if (image == null) { string fileNamePng = fileNameNoExt + ".png"; image = GetImage(fileNamePng); } return image; } public static Image GetImage(string fileName) { Stream stream = GetResourceStream(fileName); Image image = null; if (stream != null) { image = LoadImage(stream); } return image; } public static Icon GetIcon(string fileName) { Stream stream = GetResourceStream(fileName); Icon icon = null; if (stream != null) { icon = new Icon(stream); } return icon; } public static Icon GetIconFromImage(string fileName) { Stream stream = GetResourceStream(fileName); Icon icon = null; if (stream != null) { Image image = LoadImage(stream); icon = Icon.FromHandle(((Bitmap)image).GetHicon()); image.Dispose(); stream.Close(); } return icon; } private static bool CheckForSignature(Stream input, byte[] signature) { long oldPos = input.Position; byte[] inputSig = new byte[signature.Length]; int amountRead = input.Read(inputSig, 0, inputSig.Length); bool foundSig = false; if (amountRead == signature.Length) { foundSig = true; for (int i = 0; i < signature.Length; ++i) { foundSig &= (signature[i] == inputSig[i]); } } input.Position = oldPos; return foundSig; } public static bool IsGdiPlusImageAllowed(Stream input) { byte[] wmfSig = new byte[] { 0xd7, 0xcd, 0xc6, 0x9a }; byte[] emfSig = new byte[] { 0x01, 0x00, 0x00, 0x00 }; // Check for and explicitely block WMF and EMF images return !(CheckForSignature(input, emfSig) || CheckForSignature(input, wmfSig)); } public static Image LoadImage(string fileName) { using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { return LoadImage(stream); } } /// /// Loads an image from the given stream. The stream must be seekable. /// /// The Stream to load the image from. public static Image LoadImage(Stream input) { /* if (!IsGdiPlusImageAllowed(input)) { throw new IOException("File format is not supported"); } */ Image image = Image.FromStream(input); if (image.RawFormat == ImageFormat.Wmf || image.RawFormat == ImageFormat.Emf) { image.Dispose(); throw new IOException("File format isn't supported"); } return image; } } }