/* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2013 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ using Greenshot.IniFile; using Greenshot.Plugin; using System; using System.Collections; using System.IO; using System.Text.RegularExpressions; using System.Windows.Forms; namespace GreenshotPlugin.Core { public static class FilenameHelper { private static readonly Regex VAR_REGEXP = new Regex(@"\${(?[^:}]+)[:]?(?[^}]*)}", RegexOptions.Compiled); private static readonly Regex SPLIT_REGEXP = new Regex(";(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", RegexOptions.Compiled); private const int MAX_TITLE_LENGTH = 80; private static CoreConfiguration conf = IniConfig.GetIniSection(); private const string UNSAFE_REPLACEMENT = "_"; /// /// Remove invalid characters from the fully qualified filename /// /// string with the full path to a file /// string with the full path to a file, without invalid characters public static string MakeFQFilenameSafe(string fullPath) { string path = MakePathSafe(Path.GetDirectoryName(fullPath)); string filename = MakeFilenameSafe(Path.GetFileName(fullPath)); // Make the fullpath again and return return Path.Combine(path, filename); } /// /// Remove invalid characters from the filename /// /// string with the full path to a file /// string with the full path to a file, without invalid characters public static string MakeFilenameSafe(string filename) { // Make the filename save! if (filename != null) { foreach (char disallowed in Path.GetInvalidFileNameChars()) { filename = filename.Replace(disallowed.ToString(), UNSAFE_REPLACEMENT); } } return filename; } /// /// Remove invalid characters from the path /// /// string with the full path to a file /// string with the full path to a file, without invalid characters public static string MakePathSafe(string path) { // Make the path save! if (path != null) { foreach (char disallowed in Path.GetInvalidPathChars()) { path = path.Replace(disallowed.ToString(), UNSAFE_REPLACEMENT); } } return path; } public static string GetFilenameWithoutExtensionFromPattern(string pattern) { return GetFilenameWithoutExtensionFromPattern(pattern, null); } public static string GetFilenameWithoutExtensionFromPattern(string pattern, ICaptureDetails captureDetails) { return FillPattern(pattern, captureDetails, true); } public static string GetFilenameFromPattern(string pattern, OutputFormat imageFormat) { return GetFilenameFromPattern(pattern, imageFormat, null); } public static string GetFilenameFromPattern(string pattern, OutputFormat imageFormat, ICaptureDetails captureDetails) { return FillPattern(pattern, captureDetails, true) + "." + imageFormat.ToString().ToLower(); } /// /// Return a filename for the current image format (png,jpg etc) with the default file pattern /// that is specified in the configuration /// /// A string with the format /// The filename which should be used to save the image public static string GetFilename(OutputFormat format, ICaptureDetails captureDetails) { string pattern = conf.OutputFileFilenamePattern; if (pattern == null || string.IsNullOrEmpty(pattern.Trim())) { pattern = "greenshot ${capturetime}"; } return GetFilenameFromPattern(pattern, format, captureDetails); } /// /// This method will be called by the regexp.replace as a MatchEvaluator delegate! /// Will delegate this to the MatchVarEvaluatorInternal and catch any exceptions /// What are we matching? /// The detail, can be null /// Variables from the process /// Variables from the user /// Variables from the machine /// string with the match replacement private static string MatchVarEvaluator(Match match, ICaptureDetails captureDetails, IDictionary processVars, IDictionary userVars, IDictionary machineVars, bool filenameSafeMode) { try { return MatchVarEvaluatorInternal(match, captureDetails, processVars, userVars, machineVars, filenameSafeMode); } catch (Exception e) { LOG.Error("Error in MatchVarEvaluatorInternal", e); } return ""; } /// /// This method will be called by the regexp.replace as a MatchEvaluator delegate! /// /// What are we matching? /// The detail, can be null /// private static string MatchVarEvaluatorInternal(Match match, ICaptureDetails captureDetails, IDictionary processVars, IDictionary userVars, IDictionary machineVars, bool filenameSafeMode) { // some defaults int padWidth = 0; int startIndex = 0; int endIndex = 0; char padChar = ' '; string dateFormat = "yyyy-MM-dd HH-mm-ss"; string replaceValue = ""; string variable = match.Groups["variable"].Value; string parameters = match.Groups["parameters"].Value; if (parameters != null && parameters.Length > 0) { string[] parms = SPLIT_REGEXP.Split(parameters); foreach (string parameter in parms) { switch (parameter.Substring(0, 1)) { case "p": string[] padParams = parameter.Substring(1).Split(new char[] { ',' }); try { padWidth = int.Parse(padParams[0]); } catch { }; if (padParams.Length > 1) { padChar = padParams[1][0]; } break; case "d": dateFormat = parameter.Substring(1); if (dateFormat.StartsWith("\"")) { dateFormat = dateFormat.Substring(1); } if (dateFormat.EndsWith("\"")) { dateFormat = dateFormat.Substring(0, dateFormat.Length - 1); } break; case "s": string range = parameter.Substring(1); string[] rangelist = range.Split(new char[] { ',' }); if (rangelist.Length > 0) { try { startIndex = int.Parse(rangelist[0]); } catch { // Ignore } } if (rangelist.Length > 1) { try { endIndex = int.Parse(rangelist[1]); } catch { // Ignore } } break; } } } if (processVars != null && processVars.Contains(variable)) { replaceValue = (string)processVars[variable]; if (filenameSafeMode) { replaceValue = MakePathSafe(replaceValue); } } else if (userVars != null && userVars.Contains(variable)) { replaceValue = (string)userVars[variable]; if (filenameSafeMode) { replaceValue = MakePathSafe(replaceValue); } } else if (machineVars != null && machineVars.Contains(variable)) { replaceValue = (string)machineVars[variable]; if (filenameSafeMode) { replaceValue = MakePathSafe(replaceValue); } } else if (captureDetails != null && captureDetails.MetaData != null && captureDetails.MetaData.ContainsKey(variable)) { replaceValue = captureDetails.MetaData[variable]; if (filenameSafeMode) { replaceValue = MakePathSafe(replaceValue); } } else { // Handle other variables // Default use "now" for the capture take´n DateTime capturetime = DateTime.Now; // Use default application name for title string title = Application.ProductName; // Check if we have capture details if (captureDetails != null) { capturetime = captureDetails.DateTime; if (captureDetails.Title != null) { title = captureDetails.Title; if (title.Length > MAX_TITLE_LENGTH) { title = title.Substring(0, MAX_TITLE_LENGTH); } } } switch (variable) { case "domain": replaceValue = Environment.UserDomainName; break; case "user": replaceValue = Environment.UserName; break; case "hostname": replaceValue = Environment.MachineName; break; case "YYYY": if (padWidth == 0) { padWidth = -4; padChar = '0'; } replaceValue = capturetime.Year.ToString(); break; case "MM": replaceValue = capturetime.Month.ToString(); if (padWidth == 0) { padWidth = -2; padChar = '0'; } break; case "DD": replaceValue = capturetime.Day.ToString(); if (padWidth == 0) { padWidth = -2; padChar = '0'; } break; case "hh": if (padWidth == 0) { padWidth = -2; padChar = '0'; } replaceValue = capturetime.Hour.ToString(); break; case "mm": if (padWidth == 0) { padWidth = -2; padChar = '0'; } replaceValue = capturetime.Minute.ToString(); break; case "ss": if (padWidth == 0) { padWidth = -2; padChar = '0'; } replaceValue = capturetime.Second.ToString(); break; case "now": replaceValue = DateTime.Now.ToString(dateFormat); if (filenameSafeMode) { replaceValue = MakeFilenameSafe(replaceValue); } break; case "capturetime": replaceValue = capturetime.ToString(dateFormat); if (filenameSafeMode) { replaceValue = MakeFilenameSafe(replaceValue); } break; case "NUM": conf.OutputFileIncrementingNumber++; IniConfig.Save(); replaceValue = conf.OutputFileIncrementingNumber.ToString(); if (padWidth == 0) { padWidth = -6; padChar = '0'; } break; case "title": replaceValue = title; if (filenameSafeMode) { replaceValue = MakeFilenameSafe(replaceValue); } break; case "MyPictures": replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures); break; case "MyMusic": replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.MyMusic); break; case "MyDocuments": replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); break; case "Personal": replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.Personal); break; case "Desktop": replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); break; case "ApplicationData": replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); break; case "LocalApplicationData": replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); break; } } // do padding if (padWidth > 0) { replaceValue = replaceValue.PadRight(padWidth, padChar); } else if (padWidth < 0) { replaceValue = replaceValue.PadLeft(-padWidth, padChar); } // do substring if (startIndex != 0 || endIndex != 0) { if (startIndex < 0) { startIndex = replaceValue.Length + startIndex; } if (endIndex < 0) { endIndex = replaceValue.Length + endIndex; } if (endIndex != 0) { try { replaceValue = replaceValue.Substring(startIndex, endIndex); } catch { // Ignore } } else { try { replaceValue = replaceValue.Substring(startIndex); } catch { // Ignore } } } return replaceValue; } /// /// "Simply" fill the pattern with environment variables /// /// String with pattern ${var} /// true to make sure everything is filenamesafe /// Filled string public static string FillVariables(string pattern, bool filenameSafeMode) { IDictionary processVars = null; IDictionary userVars = null; IDictionary machineVars = null; try { processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); } catch (Exception e) { LOG.Error("Error retrieving EnvironmentVariableTarget.Process", e); } try { userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); } catch (Exception e) { LOG.Error("Error retrieving EnvironmentVariableTarget.User", e); } try { machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); } catch (Exception e) { LOG.Error("Error retrieving EnvironmentVariableTarget.Machine", e); } return VAR_REGEXP.Replace(pattern, delegate(Match m) { return MatchVarEvaluator(m, null, processVars, userVars, machineVars, filenameSafeMode); } ); } /// /// Fill the pattern wit the supplied details /// /// Pattern /// CaptureDetails /// Should the result be made "filename" safe? /// Filled pattern public static string FillPattern(string pattern, ICaptureDetails captureDetails, bool filenameSafeMode) { IDictionary processVars = null; IDictionary userVars = null; IDictionary machineVars = null; try { processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); } catch (Exception e) { LOG.Error("Error retrieving EnvironmentVariableTarget.Process", e); } try { userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); } catch (Exception e) { LOG.Error("Error retrieving EnvironmentVariableTarget.User", e); } try { machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); } catch (Exception e) { LOG.Error("Error retrieving EnvironmentVariableTarget.Machine", e); } try { return VAR_REGEXP.Replace(pattern, delegate(Match m) { return MatchVarEvaluator(m, captureDetails, processVars, userVars, machineVars, filenameSafeMode); } ); } catch (Exception e) { // adding additional data for bug tracking e.Data.Add("title", captureDetails.Title); e.Data.Add("pattern", pattern); throw; } } } }