using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Web; using SabreTools.Library.Data; using SabreTools.Library.DatFiles; #if MONO using System.IO; #else using Alphaleonis.Win32.Filesystem; using FileStream = System.IO.FileStream; #endif namespace SabreTools.Library.Tools { /// /// Include character normalization and replacement mappings /// public static class Style { #region DAT Cleaning /// /// Clean a game (or rom) name to the WoD standard /// /// Name of the game to be cleaned /// The cleaned name public static string CleanGameName(string game) { ///Run the name through the filters to make sure that it's correct game = NormalizeChars(game); game = RussianToLatin(game); game = SearchPattern(game); game = new Regex(@"(([[(].*[\)\]] )?([^([]+))").Match(game).Groups[1].Value; game = game.TrimStart().TrimEnd(); return game; } /// /// Clean a game (or rom) name to the WoD standard /// /// Array representing the path to be cleaned /// The cleaned name public static string CleanGameName(string[] game) { game[game.Length - 1] = CleanGameName(game[game.Length - 1]); string outgame = String.Join(Path.DirectorySeparatorChar.ToString(), game); outgame = outgame.TrimStart().TrimEnd(); return outgame; } /// /// Clean a hash string and pad to the correct size /// /// Hash string to sanitize /// Amount of characters to pad to /// Cleaned string public static string CleanHashData(string hash, int padding) { // If we have a known blank hash, return blank if (string.IsNullOrEmpty(hash) || hash == "-" || hash == "_") { return ""; } // Check to see if it's a "hex" hash hash = hash.Trim().Replace("0x", ""); // If we have a blank hash now, return blank if (string.IsNullOrEmpty(hash)) { return ""; } // If the hash shorter than the required length, pad it if (hash.Length < padding) { hash = hash.PadLeft(padding, '0'); } // If the hash is longer than the required length, it's invalid else if (hash.Length > padding) { return ""; } // Now normalize the hash hash = hash.ToLowerInvariant(); // Otherwise, make sure that every character is a proper match for (int i = 0; i < hash.Length; i++) { if ((hash[i] < '0' || hash[i] > '9') && (hash[i] < 'a' || hash[i] > 'f')) { hash = ""; break; } } return hash; } /// /// Clean a hash string from a Listrom DAT /// /// Hash string to sanitize /// Cleaned string public static string CleanListromHashData(string hash) { if (hash.StartsWith("CRC")) { return hash.Substring(4, 8).ToLowerInvariant(); } else if (hash.StartsWith("SHA1")) { return hash.Substring(5, 40).ToLowerInvariant(); } return hash; } /// /// Generate a proper outfile name based on a DAT and output directory /// /// Output directory /// DAT information /// True if we ignore existing files (default), false otherwise /// Dictionary of output formats mapped to file names public static Dictionary CreateOutfileNames(string outDir, DatFile datdata, bool overwrite = true) { // Create the output dictionary Dictionary outfileNames = new Dictionary(); // Double check the outDir for the end delim if (!outDir.EndsWith(Path.DirectorySeparatorChar.ToString())) { outDir += Path.DirectorySeparatorChar; } // Get the extensions from the output type // AttractMode if ((datdata.DatFormat & DatFormat.AttractMode) != 0) { outfileNames.Add(DatFormat.AttractMode, CreateOutfileNamesHelper(outDir, ".txt", datdata, overwrite)); } // ClrMamePro if ((datdata.DatFormat & DatFormat.ClrMamePro) != 0) { outfileNames.Add(DatFormat.ClrMamePro, CreateOutfileNamesHelper(outDir, ".dat", datdata, overwrite)); }; // CSV if ((datdata.DatFormat & DatFormat.CSV) != 0) { outfileNames.Add(DatFormat.CSV, CreateOutfileNamesHelper(outDir, ".csv", datdata, overwrite)); }; // DOSCenter if ((datdata.DatFormat & DatFormat.DOSCenter) != 0 && (datdata.DatFormat & DatFormat.ClrMamePro) == 0 && (datdata.DatFormat & DatFormat.RomCenter) == 0) { outfileNames.Add(DatFormat.DOSCenter, CreateOutfileNamesHelper(outDir, ".dat", datdata, overwrite)); }; if ((datdata.DatFormat & DatFormat.DOSCenter) != 0 && ((datdata.DatFormat & DatFormat.ClrMamePro) != 0 || (datdata.DatFormat & DatFormat.RomCenter) != 0)) { outfileNames.Add(DatFormat.DOSCenter, CreateOutfileNamesHelper(outDir, ".dc.dat", datdata, overwrite)); } //MAME Listroms if ((datdata.DatFormat & DatFormat.Listroms) != 0 && (datdata.DatFormat & DatFormat.AttractMode) == 0) { outfileNames.Add(DatFormat.Listroms, CreateOutfileNamesHelper(outDir, ".txt", datdata, overwrite)); } if ((datdata.DatFormat & DatFormat.Listroms) != 0 && (datdata.DatFormat & DatFormat.AttractMode) != 0) { outfileNames.Add(DatFormat.Listroms, CreateOutfileNamesHelper(outDir, ".lr.txt", datdata, overwrite)); } // Logiqx XML if ((datdata.DatFormat & DatFormat.Logiqx) != 0) { outfileNames.Add(DatFormat.Logiqx, CreateOutfileNamesHelper(outDir, ".xml", datdata, overwrite)); } // Missfile if ((datdata.DatFormat & DatFormat.MissFile) != 0 && (datdata.DatFormat & DatFormat.AttractMode) == 0) { outfileNames.Add(DatFormat.MissFile, CreateOutfileNamesHelper(outDir, ".txt", datdata, overwrite)); } if ((datdata.DatFormat & DatFormat.MissFile) != 0 && (datdata.DatFormat & DatFormat.AttractMode) != 0) { outfileNames.Add(DatFormat.MissFile, CreateOutfileNamesHelper(outDir, ".miss.txt", datdata, overwrite)); } // OfflineList if (((datdata.DatFormat & DatFormat.OfflineList) != 0) && (datdata.DatFormat & DatFormat.Logiqx) == 0 && (datdata.DatFormat & DatFormat.SabreDat) == 0 && (datdata.DatFormat & DatFormat.SoftwareList) == 0) { outfileNames.Add(DatFormat.OfflineList, CreateOutfileNamesHelper(outDir, ".xml", datdata, overwrite)); } if (((datdata.DatFormat & DatFormat.OfflineList) != 0 && ((datdata.DatFormat & DatFormat.Logiqx) != 0 || (datdata.DatFormat & DatFormat.SabreDat) != 0 || (datdata.DatFormat & DatFormat.SoftwareList) != 0))) { outfileNames.Add(DatFormat.OfflineList, CreateOutfileNamesHelper(outDir, ".ol.xml", datdata, overwrite)); } // Redump MD5 if ((datdata.DatFormat & DatFormat.RedumpMD5) != 0) { outfileNames.Add(DatFormat.RedumpMD5, CreateOutfileNamesHelper(outDir, ".md5", datdata, overwrite)); }; // Redump SFV if ((datdata.DatFormat & DatFormat.RedumpSFV) != 0) { outfileNames.Add(DatFormat.RedumpSFV, CreateOutfileNamesHelper(outDir, ".sfv", datdata, overwrite)); }; // Redump SHA-1 if ((datdata.DatFormat & DatFormat.RedumpSHA1) != 0) { outfileNames.Add(DatFormat.RedumpSHA1, CreateOutfileNamesHelper(outDir, ".sha1", datdata, overwrite)); }; // Redump SHA-256 if ((datdata.DatFormat & DatFormat.RedumpSHA256) != 0) { outfileNames.Add(DatFormat.RedumpSHA256, CreateOutfileNamesHelper(outDir, ".sha256", datdata, overwrite)); }; // RomCenter if ((datdata.DatFormat & DatFormat.RomCenter) != 0 && (datdata.DatFormat & DatFormat.ClrMamePro) == 0) { outfileNames.Add(DatFormat.RomCenter, CreateOutfileNamesHelper(outDir, ".dat", datdata, overwrite)); }; if ((datdata.DatFormat & DatFormat.RomCenter) != 0 && (datdata.DatFormat & DatFormat.ClrMamePro) != 0) { outfileNames.Add(DatFormat.RomCenter, CreateOutfileNamesHelper(outDir, ".rc.dat", datdata, overwrite)); }; // SabreDAT if ((datdata.DatFormat & DatFormat.SabreDat) != 0 && (datdata.DatFormat & DatFormat.Logiqx) == 0) { outfileNames.Add(DatFormat.SabreDat, CreateOutfileNamesHelper(outDir, ".xml", datdata, overwrite)); }; if ((datdata.DatFormat & DatFormat.SabreDat) != 0 && (datdata.DatFormat & DatFormat.Logiqx) != 0) { outfileNames.Add(DatFormat.SabreDat, CreateOutfileNamesHelper(outDir, ".sd.xml", datdata, overwrite)); }; // Software List if ((datdata.DatFormat & DatFormat.SoftwareList) != 0 && (datdata.DatFormat & DatFormat.Logiqx) == 0 && (datdata.DatFormat & DatFormat.SabreDat) == 0) { outfileNames.Add(DatFormat.SoftwareList, CreateOutfileNamesHelper(outDir, ".xml", datdata, overwrite)); } if ((datdata.DatFormat & DatFormat.SoftwareList) != 0 && ((datdata.DatFormat & DatFormat.Logiqx) != 0 || (datdata.DatFormat & DatFormat.SabreDat) != 0)) { outfileNames.Add(DatFormat.SoftwareList, CreateOutfileNamesHelper(outDir, ".sl.xml", datdata, overwrite)); } // TSV if ((datdata.DatFormat & DatFormat.TSV) != 0) { outfileNames.Add(DatFormat.TSV, CreateOutfileNamesHelper(outDir, ".tsv", datdata, overwrite)); }; return outfileNames; } /// /// Help generating the outfile name /// /// Output directory /// Extension to use for the file /// DAT information /// True if we ignore existing files, false otherwise /// String containing the new filename private static string CreateOutfileNamesHelper(string outDir, string extension, DatFile datdata, bool overwrite) { string filename = (String.IsNullOrEmpty(datdata.FileName) ? datdata.Description : datdata.FileName); string outfile = outDir + filename + extension; outfile = (outfile.Contains(Path.DirectorySeparatorChar.ToString() + Path.DirectorySeparatorChar.ToString()) ? outfile.Replace(Path.DirectorySeparatorChar.ToString() + Path.DirectorySeparatorChar.ToString(), Path.DirectorySeparatorChar.ToString()) : outfile); if (!overwrite) { int i = 1; while (File.Exists(outfile)) { outfile = outDir + filename + "_" + i + extension; outfile = (outfile.Contains(Path.DirectorySeparatorChar.ToString() + Path.DirectorySeparatorChar.ToString()) ? outfile.Replace(Path.DirectorySeparatorChar.ToString() + Path.DirectorySeparatorChar.ToString(), Path.DirectorySeparatorChar.ToString()) : outfile); i++; } } return outfile; } /// /// Get the proper extension for the stat output format /// /// Output path to use /// StatDatFormat to get the extension for /// Name of the input file to use /// Dictionary of output formats mapped to file names public static Dictionary CreateOutStatsNames(string outDir, StatDatFormat statDatFormat, string reportName, bool overwrite = true) { Dictionary output = new Dictionary(); // First try to create the output directory if we need to if (!Directory.Exists(outDir)) { Directory.CreateDirectory(outDir); } // For each output format, get the appropriate stream writer if ((statDatFormat & StatDatFormat.None) != 0) { output.Add(StatDatFormat.None, CreateOutStatsNamesHelper(outDir, ".txt", reportName, overwrite)); } if ((statDatFormat & StatDatFormat.CSV) != 0) { output.Add(StatDatFormat.CSV, CreateOutStatsNamesHelper(outDir, ".csv", reportName, overwrite)); } if ((statDatFormat & StatDatFormat.HTML) != 0) { output.Add(StatDatFormat.HTML, CreateOutStatsNamesHelper(outDir, ".html", reportName, overwrite)); } if ((statDatFormat & StatDatFormat.TSV) != 0) { output.Add(StatDatFormat.TSV, CreateOutStatsNamesHelper(outDir, ".tsv", reportName, overwrite)); } return output; } /// /// Help generating the outstats name /// /// Output directory /// Extension to use for the file /// Name of the input file to use /// True if we ignore existing files, false otherwise /// String containing the new filename private static string CreateOutStatsNamesHelper(string outDir, string extension, string reportName, bool overwrite) { string outfile = outDir + reportName + extension; outfile = (outfile.Contains(Path.DirectorySeparatorChar.ToString() + Path.DirectorySeparatorChar.ToString()) ? outfile.Replace(Path.DirectorySeparatorChar.ToString() + Path.DirectorySeparatorChar.ToString(), Path.DirectorySeparatorChar.ToString()) : outfile); if (!overwrite) { int i = 1; while (File.Exists(outfile)) { outfile = outDir + reportName + "_" + i + extension; outfile = (outfile.Contains(Path.DirectorySeparatorChar.ToString() + Path.DirectorySeparatorChar.ToString()) ? outfile.Replace(Path.DirectorySeparatorChar.ToString() + Path.DirectorySeparatorChar.ToString(), Path.DirectorySeparatorChar.ToString()) : outfile); i++; } } return outfile; } #endregion #region String Manipulation /// /// Compare strings as numeric /// /// First string to compare /// Second string to compare /// -1 if s1 comes before s2, 0 if s1 and s2 are equal, 1 if s1 comes after s2 /// I want to be able to handle paths properly with no issue, can I do a recursive call based on separated by path separator? public static int CompareNumeric(string s1, string s2) { // Save the orginal strings, for later comparison string s1orig = s1; string s2orig = s2; // We want to normalize the strings, so we set both to lower case s1 = s1.ToLowerInvariant(); s2 = s2.ToLowerInvariant(); // If the strings are the same exactly, return if (s1 == s2) { return s1orig.CompareTo(s2orig); } // If one is null, then say that's less than if (s1 == null) { return -1; } if (s2 == null) { return 1; } // Now split into path parts after converting AltDirSeparator to DirSeparator s1 = s1.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); s2 = s2.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); string[] s1parts = s1.Split(Path.DirectorySeparatorChar); string[] s2parts = s2.Split(Path.DirectorySeparatorChar); // Then compare each part in turn for (int j = 0; j < s1parts.Length && j < s2parts.Length; j++) { int compared = CompareNumericPart(s1parts[j], s2parts[j]); if (compared != 0) { return compared; } } // If we got out here, then it looped through at least one of the strings if (s1parts.Length > s2parts.Length) { return 1; } if (s1parts.Length < s2parts.Length) { return -1; } return s1orig.CompareTo(s2orig); } /// /// Helper for CompareNumeric /// /// First string to compare /// Second string to compare /// -1 if s1 comes before s2, 0 if s1 and s2 are equal, 1 if s1 comes after s2 private static int CompareNumericPart(string s1, string s2) { // Otherwise, loop through until we have an answer for (int i = 0; i < s1.Length && i < s2.Length; i++) { int s1c = s1[i]; int s2c = s2[i]; // If the characters are the same, continue if (s1c == s2c) { continue; } // If they're different, check which one was larger if (s1c > s2c) { return 1; } if (s1c < s2c) { return -1; } } // If we got out here, then it looped through at least one of the strings if (s1.Length > s2.Length) { return 1; } if (s1.Length < s2.Length) { return -1; } return 0; } /// /// Convert all characters that are not considered XML-safe /// /// Input string to clean /// Cleaned string public static string ConvertXMLUnsafeCharacters(string s) { return new String(s.Select(c => (c == 0x9 || c == 0xA || c == 0xD || (c >= 0x20 && c <= 0xD77F) || (c >= 0xE000 && c <= 0xFFFD) || (c >= 0x10000 && c <= 0x10FFFF) ? c : HttpUtility.HtmlEncode(c)[0])) .ToArray()); } /// /// Get a proper romba sub path /// /// SHA-1 hash to get the path for /// Subfolder path for the given hash public static string GetRombaPath(string hash) { // If the hash isn't the right size, then we return null if (hash.Length != Constants.SHA1Length) // TODO: When updating to SHA-256, this needs to update to Constants.SHA256Length { return null; } return Path.Combine(hash.Substring(0, 2), hash.Substring(2, 2), hash.Substring(4, 2), hash.Substring(6, 2), hash + ".gz"); } /// /// Get the multiplier to be used with the size given /// /// String with possible size with extension /// Tuple of multiplier to use on final size and fixed size string public static long GetSizeFromString(string sizestring) { long size = 0; // Make sure the string is in lower case sizestring = sizestring.ToLowerInvariant(); // Get any trailing size identifiers long multiplier = 1; if (sizestring.EndsWith("k") || sizestring.EndsWith("kb")) { multiplier = Constants.KiloByte; } else if (sizestring.EndsWith("ki") || sizestring.EndsWith("kib")) { multiplier = Constants.KibiByte; } else if (sizestring.EndsWith("m") || sizestring.EndsWith("mb")) { multiplier = Constants.MegaByte; } else if (sizestring.EndsWith("mi") || sizestring.EndsWith("mib")) { multiplier = Constants.MibiByte; } else if (sizestring.EndsWith("g") || sizestring.EndsWith("gb")) { multiplier = Constants.GigaByte; } else if (sizestring.EndsWith("gi") || sizestring.EndsWith("gib")) { multiplier = Constants.GibiByte; } else if (sizestring.EndsWith("t") || sizestring.EndsWith("tb")) { multiplier = Constants.TeraByte; } else if (sizestring.EndsWith("ti") || sizestring.EndsWith("tib")) { multiplier = Constants.TibiByte; } else if (sizestring.EndsWith("p") || sizestring.EndsWith("pb")) { multiplier = Constants.PetaByte; } else if (sizestring.EndsWith("pi") || sizestring.EndsWith("pib")) { multiplier = Constants.PibiByte; } // Remove any trailing identifiers sizestring = sizestring.TrimEnd(new char[] { 'k', 'm', 'g', 't', 'p', 'i', 'b', ' ' }); // Now try to get the size from the string if (!Int64.TryParse(sizestring, out size)) { size = -1; } else { size *= multiplier; } return size; } /// /// Get if a string contains Unicode characters /// /// Input string to test /// True if the string contains at least one Unicode character, false otherwise public static bool IsUnicode(string s) { return (s.Any(c => c > 255)); } /// /// Remove all chars that are considered path unsafe /// /// Input string to clean /// Cleaned string public static string RemovePathUnsafeCharacters(string s) { List invalidPath = Path.GetInvalidPathChars().ToList(); return new string(s.Where(c => !invalidPath.Contains(c)).ToArray()); } /// /// Remove all unicode-specific chars from a string /// /// Input string to clean /// Cleaned string public static string RemoveUnicodeCharacters(string s) { return new string(s.Where(c => c <= 255).ToArray()); } /// /// Split a line as if it were a CMP rom line /// /// Line to split /// Line split /// Uses code from http://stackoverflow.com/questions/554013/regular-expression-to-split-on-spaces-unless-in-quotes public static string[] SplitLineAsCMP(string s) { // Get the opening and closing brace locations int openParenLoc = s.IndexOf('('); int closeParenLoc = s.LastIndexOf(')'); // Now remove anything outside of those braces, including the braces s = s.Substring(openParenLoc + 1, closeParenLoc - openParenLoc - 1); s = s.Trim(); // Now we get each string, divided up as cleanly as possible string[] matches = Regex //.Matches(s, @"([^\s]*""[^""]+""[^\s]*)|[^""]?\w+[^""]?") .Matches(s, @"[^\s""]+|""[^""]*""") .Cast() .Select(m => m.Groups[0].Value) .ToArray(); return matches; } #endregion #region System.IO.Path Replacements /// /// Replacement for System.IO.Path.GetDirectoryName /// /// Path to get directory name out of /// Directory name from path /// public static string GetDirectoryName(string s) { if (s == null) { return ""; } if (s.Contains("/")) { string[] tempkey = s.Split('/'); return String.Join("/", tempkey.Take(tempkey.Length - 1)); } else if (s.Contains("\\")) { string[] tempkey = s.Split('\\'); return String.Join("\\", tempkey.Take(tempkey.Length - 1)); } return ""; } /// /// Replacement for System.IO.Path.GetFileName /// /// Path to get file name out of /// File name from path /// public static string GetFileName(string s) { if (s == null) { return ""; } if (s.Contains("/")) { string[] tempkey = s.Split('/'); return tempkey.Last(); } else if (s.Contains("\\")) { string[] tempkey = s.Split('\\'); return tempkey.Last(); } return s; } /// /// Replacement for System.IO.Path.GetFileNameWithoutExtension /// /// Path to get file name out of /// File name without extension from path /// public static string GetFileNameWithoutExtension(string s) { s = GetFileName(s); string[] tempkey = s.Split('.'); if (tempkey.Count() == 1) { return s; } return String.Join(".", tempkey.Take(tempkey.Length - 1)); } #endregion #region WoD-based String Cleaning /// /// Replace accented characters /// /// String to be parsed /// String with characters replaced public static string NormalizeChars(string input) { string[,] charmap = { { "Á", "A" }, { "á", "a" }, { "À", "A" }, { "à", "a" }, { "Â", "A" }, { "â", "a" }, { "Ä", "Ae" }, { "ä", "ae" }, { "Ã", "A" }, { "ã", "a" }, { "Å", "A" }, { "å", "a" }, { "Æ", "Ae" }, { "æ", "ae" }, { "Ç", "C" }, { "ç", "c" }, { "Ð", "D" }, { "ð", "d" }, { "É", "E" }, { "é", "e" }, { "È", "E" }, { "è", "e" }, { "Ê", "E" }, { "ê", "e" }, { "Ë", "E" }, { "ë", "e" }, { "ƒ", "f" }, { "Í", "I" }, { "í", "i" }, { "Ì", "I" }, { "ì", "i" }, { "Î", "I" }, { "î", "i" }, { "Ï", "I" }, { "ï", "i" }, { "Ñ", "N" }, { "ñ", "n" }, { "Ó", "O" }, { "ó", "o" }, { "Ò", "O" }, { "ò", "o" }, { "Ô", "O" }, { "ô", "o" }, { "Ö", "Oe" }, { "ö", "oe" }, { "Õ", "O" }, { "õ", "o" }, { "Ø", "O" }, { "ø", "o" }, { "Š", "S" }, { "š", "s" }, { "ß", "ss" }, { "Þ", "B" }, { "þ", "b" }, { "Ú", "U" }, { "ú", "u" }, { "Ù", "U" }, { "ù", "u" }, { "Û", "U" }, { "û", "u" }, { "Ü", "Ue" }, { "ü", "ue" }, { "ÿ", "y" }, { "Ý", "Y" }, { "ý", "y" }, { "Ž", "Z" }, { "ž", "z" }, }; for (int i = 0; i < charmap.GetLength(0); i++) { input = input.Replace(charmap[i, 0], charmap[i, 1]); } return input; } /// /// Convert Cyrillic lettering to Latin lettering /// /// String to be parsed /// String with characters replaced public static string RussianToLatin(string input) { string[,] charmap = { { "А", "A" }, { "Б", "B" }, { "В", "V" }, { "Г", "G" }, { "Д", "D" }, { "Е", "E" }, { "Ё", "Yo" }, { "Ж", "Zh" }, { "З", "Z" }, { "И", "I" }, { "Й", "J" }, { "К", "K" }, { "Л", "L" }, { "М", "M" }, { "Н", "N" }, { "О", "O" }, { "П", "P" }, { "Р", "R" }, { "С", "S" }, { "Т", "T" }, { "У", "U" }, { "Ф", "f" }, { "Х", "Kh" }, { "Ц", "Ts" }, { "Ч", "Ch" }, { "Ш", "Sh" }, { "Щ", "Sch" }, { "Ъ", "" }, { "Ы", "y" }, { "Ь", "" }, { "Э", "e" }, { "Ю", "yu" }, { "Я", "ya" }, { "а", "a" }, { "б", "b" }, { "в", "v" }, { "г", "g" }, { "д", "d" }, { "е", "e" }, { "ё", "yo" }, { "ж", "zh" }, { "з", "z" }, { "и", "i" }, { "й", "j" }, { "к", "k" }, { "л", "l" }, { "м", "m" }, { "н", "n" }, { "о", "o" }, { "п", "p" }, { "р", "r" }, { "с", "s" }, { "т", "t" }, { "у", "u" }, { "ф", "f" }, { "х", "kh" }, { "ц", "ts" }, { "ч", "ch" }, { "ш", "sh" }, { "щ", "sch" }, { "ъ", "" }, { "ы", "y" }, { "ь", "" }, { "э", "e" }, { "ю", "yu" }, { "я", "ya" }, }; for (int i = 0; i < charmap.GetLength(0); i++) { input = input.Replace(charmap[i, 0], charmap[i, 1]); } return input; } /// /// Replace special characters and patterns /// /// String to be parsed /// String with characters replaced public static string SearchPattern(string input) { string[,] charmap = { { @"~", " - " }, { @"_", " " }, { @":", " " }, { @">", ")" }, { @"<", "(" }, { @"\|", "-" }, { "\"", "'" }, { @"\*", "." }, { @"\\", "-" }, { @"/", "-" }, { @"\?", " " }, { @"\(([^)(]*)\(([^)]*)\)([^)(]*)\)", " " }, { @"\(([^)]+)\)", " " }, { @"\[([^]]+)\]", " " }, { @"\{([^}]+)\}", " " }, { @"(ZZZJUNK|ZZZ-UNK-|ZZZ-UNK |zzz unknow |zzz unk |Copy of |[.][a-z]{3}[.][a-z]{3}[.]|[.][a-z]{3}[.])", " " }, { @" (r|rev|v|ver)\s*[\d\.]+[^\s]*", " " }, { @"(( )|(\A))(\d{6}|\d{8})(( )|(\Z))", " " }, { @"(( )|(\A))(\d{1,2})-(\d{1,2})-(\d{4}|\d{2})", " " }, { @"(( )|(\A))(\d{4}|\d{2})-(\d{1,2})-(\d{1,2})", " " }, { @"[-]+", "-" }, { @"\A\s*\)", " " }, { @"\A\s*(,|-)", " " }, { @"\s+", " " }, { @"\s+,", "," }, { @"\s*(,|-)\s*\Z", " " }, }; for (int i = 0; i < charmap.GetLength(0); i++) { input = Regex.Replace(input, charmap[i, 0], charmap[i, 1]); } return input; } #endregion #region Externally sourced methods /// /// Returns the human-readable file size for an arbitrary, 64-bit file size /// The default format is "0.### XB", e.g. "4.2 KB" or "1.434 GB" /// /// /// Human-readable file size /// http://www.somacon.com/p576.php public static string GetBytesReadable(long input) { // Get absolute value long absolute_i = (input < 0 ? -input : input); // Determine the suffix and readable value string suffix; double readable; if (absolute_i >= 0x1000000000000000) // Exabyte { suffix = "EB"; readable = (input >> 50); } else if (absolute_i >= 0x4000000000000) // Petabyte { suffix = "PB"; readable = (input >> 40); } else if (absolute_i >= 0x10000000000) // Terabyte { suffix = "TB"; readable = (input >> 30); } else if (absolute_i >= 0x40000000) // Gigabyte { suffix = "GB"; readable = (input >> 20); } else if (absolute_i >= 0x100000) // Megabyte { suffix = "MB"; readable = (input >> 10); } else if (absolute_i >= 0x400) // Kilobyte { suffix = "KB"; readable = input; } else { return input.ToString("0 B"); // Byte } // Divide by 1024 to get fractional value readable = (readable / 1024); // Return formatted number with suffix return readable.ToString("0.### ") + suffix; } /// /// http://stackoverflow.com/questions/311165/how-do-you-convert-byte-array-to-hexadecimal-string-and-vice-versa /// public static byte[] StringToByteArray(string hex) { int NumberChars = hex.Length; byte[] bytes = new byte[NumberChars / 2]; for (int i = 0; i < NumberChars; i += 2) bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); return bytes; } /// /// http://stackoverflow.com/questions/5613279/c-sharp-hex-to-ascii /// public static string ConvertHexToAscii(string hexString) { if (hexString.Contains("-")) { hexString = hexString.Replace("-", ""); } StringBuilder sb = new StringBuilder(); for (int i = 0; i < hexString.Length; i += 2) { String hs = hexString.Substring(i, 2); sb.Append(Convert.ToChar(Convert.ToUInt32(hs, 16))); } return sb.ToString(); } /// /// http://stackoverflow.com/questions/15920741/convert-from-string-ascii-to-string-hex /// public static string ConvertAsciiToHex(string asciiString) { string hexOutput = ""; foreach (char _eachChar in asciiString.ToCharArray()) { // Get the integral value of the character. int value = Convert.ToInt32(_eachChar); // Convert the decimal value to a hexadecimal value in string form. hexOutput += String.Format("{0:X2}", value).Remove(0, 2); // to make output as your eg // hexOutput +=" "+ String.Format("{0:X}", value); } return hexOutput; } /// /// Adapted from 7-zip Source Code: CPP/Windows/TimeUtils.cpp:FileTimeToDosTime /// public static uint ConvertDateTimeToMsDosTimeFormat(DateTime dateTime) { uint year = (uint)((dateTime.Year - 1980) % 128); uint mon = (uint)dateTime.Month; uint day = (uint)dateTime.Day; uint hour = (uint)dateTime.Hour; uint min = (uint)dateTime.Minute; uint sec = (uint)dateTime.Second; return (year << 25) | (mon << 21) | (day << 16) | (hour << 11) | (min << 5) | (sec >> 1); } /// /// Adapted from 7-zip Source Code: CPP/Windows/TimeUtils.cpp:DosTimeToFileTime /// public static DateTime ConvertMsDosTimeFormatToDateTime(uint msDosDateTime) { return new DateTime((int)(1980 + (msDosDateTime >> 25)), (int)((msDosDateTime >> 21) & 0xF), (int)((msDosDateTime >> 16) & 0x1F), (int)((msDosDateTime >> 11) & 0x1F), (int)((msDosDateTime >> 5) & 0x3F), (int)((msDosDateTime & 0x1F) * 2)); } /// /// Determines a text file's encoding by analyzing its byte order mark (BOM). /// Defaults to ASCII when detection of the text file's endianness fails. /// http://stackoverflow.com/questions/3825390/effective-way-to-find-any-files-encoding /// /// The text file to analyze. /// The detected encoding. public static Encoding GetEncoding(string filename) { // Read the BOM var bom = new byte[4]; FileStream file = FileTools.TryOpenRead(filename); file.Read(bom, 0, 4); file.Dispose(); // Analyze the BOM if (bom[0] == 0x2b && bom[1] == 0x2f && bom[2] == 0x76) return Encoding.UTF7; if (bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf) return Encoding.UTF8; if (bom[0] == 0xff && bom[1] == 0xfe) return Encoding.Unicode; //UTF-16LE if (bom[0] == 0xfe && bom[1] == 0xff) return Encoding.BigEndianUnicode; //UTF-16BE if (bom[0] == 0 && bom[1] == 0 && bom[2] == 0xfe && bom[3] == 0xff) return Encoding.UTF32; return Encoding.Default; } /// /// http://stackoverflow.com/questions/1600962/displaying-the-build-date /// public static DateTime GetLinkerTime(this Assembly assembly, TimeZoneInfo target = null) { var filePath = assembly.Location; const int c_PeHeaderOffset = 60; const int c_LinkerTimestampOffset = 8; var buffer = new byte[2048]; using (var stream = FileTools.TryOpenRead(filePath)) stream.Read(buffer, 0, 2048); var offset = BitConverter.ToInt32(buffer, c_PeHeaderOffset); var secondsSince1970 = BitConverter.ToInt32(buffer, offset + c_LinkerTimestampOffset); var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); var linkTimeUtc = epoch.AddSeconds(secondsSince1970); var tz = target ?? TimeZoneInfo.Local; var localTime = TimeZoneInfo.ConvertTimeFromUtc(linkTimeUtc, tz); return localTime; } #endregion } }