public static int Main(string[] args) { int result; try { ColoredConsole.WriteLine("~WOpera Speed Dial Patch for {0}~N", OperaPatches.Patches[0].StartVersion); ColoredConsole.WriteLine("~WCopyright (c) 2013 dqdb~N"); ColoredConsole.WriteLine(); ColoredConsole.WriteLine("Thanks to ~WIzer0~N for all patches."); ColoredConsole.WriteLine(); Settings settings = new Settings(); settings.LoadFromConfigFile(); settings.LoadFromConsole(); settings.SaveToConfigFile(); ColoredConsole.WriteLine(); string pakFileName = FindLatestOperaPak(settings.OperaFolder); if (pakFileName == null) { ColoredConsole.WriteLine("~r~WError:~k~R unable to find an ~r~Wopera.pak~N to patch.~N"); return(1); } OperaVersion version; try { version = GetOperaPakVersion(pakFileName); } catch (Exception) { ColoredConsole.WriteLine("~r~WError:~k~R unable to get version number from ~r~W{0}~k~R.~N", pakFileName); return(1); } ColoredConsole.WriteLine("Opera version: ~W{0}~N", version); OperaPatch operaPatch = OperaPatches.Find(version); if (operaPatch == null) { operaPatch = OperaPatches.FindWithHeuristics(settings, pakFileName); if (operaPatch == null) { ColoredConsole.WriteLine(); ColoredConsole.WriteLine("~r~WError:~k~R this Opera version is not supported yet.~N"); return(1); } ColoredConsole.WriteLine(); ColoredConsole.WriteLine("Processing ..."); ColoredConsole.WriteLine(); ColoredConsole.WriteLine("OperaExeOffset: ~W0x{0:x8}~N", operaPatch.ExePatch.Offset); ColoredConsole.WriteLine("SpeeddialLayoutJs: ~W{0}~N", operaPatch.SpeeddialLayoutJs); ColoredConsole.WriteLine("StartPageHtml: ~W{0}~N", operaPatch.StartPageHtml); ColoredConsole.WriteLine("PreinstalledSpeeddialsJs: ~W{0}~N", operaPatch.PreinstalledSpeeddialsJs); ColoredConsole.WriteLine("SpeeddialSuggestionsJs: ~W{0}~N", operaPatch.SpeeddialSuggestionsJs); ColoredConsole.WriteLine("ToolsCss: ~W{0}~N", operaPatch.ToolsCss); ColoredConsole.WriteLine("FilterCss: ~W{0}~N", operaPatch.FilterCss); ColoredConsole.WriteLine(); ColoredConsole.WriteLine("~y~KWarning:~k~Y this Opera version is probably supported, but it is ~y~KNOT~k~Y tested yet. Improper patching may have side effects.~N"); ColoredConsole.WriteLine(); if (!ColoredConsole.Read("I understand the risks: ", false)) { return(1); } ColoredConsole.WriteLine(); } else { ColoredConsole.WriteLine("Using resource layout for Opera ~W{0}~N - ~W{1}~N builds.", operaPatch.StartVersion, operaPatch.EndVersion); ColoredConsole.WriteLine(); } if (!ColoredConsole.Read("I would like to start patching: ", true)) { return(1); } ColoredConsole.WriteLine(); operaPatch.Apply(settings, pakFileName); result = 0; } catch (Exception ex) { ColoredConsole.WriteLine(); if (ex.InnerException == null) { ColoredConsole.WriteLine("~r~WError:~k~R {0}~N", ex.Message); } else { ColoredConsole.WriteLine("~r~WError:~k~R {0}~N ----> {1}", ex.Message, ex.InnerException.ToString()); } result = 1; } return(result); }
public static int Main(string[] args) { int result; try { ColoredConsole.WriteLine("~WOpera Speed Dial Patch (build 20131124)~N"); ColoredConsole.WriteLine("~WCopyright (c) 2013 dqdb~N"); ColoredConsole.WriteLine(); ColoredConsole.WriteLine("Thanks to ~WIzer0~N for all patches."); ColoredConsole.WriteLine(); Settings settings = new Settings(); settings.LoadFromConfigFile(); settings.LoadFromConsole(); settings.SaveToConfigFile(); ColoredConsole.WriteLine(); string pakFileName = FindLatestOperaPak(settings.OperaFolder); if (pakFileName == null) { ColoredConsole.WriteLine("~r~WError:~k~R unable to find an ~r~Wopera.pak~N to patch.~N"); return(1); } OperaVersion version; try { version = GetOperaPakVersion(pakFileName); } catch (Exception) { ColoredConsole.WriteLine("~r~WError:~k~R unable to get version number from ~r~W{0}~k~R.~N", pakFileName); return(1); } ColoredConsole.WriteLine("Opera version: ~W{0}~N", version); OperaPatch operaPatch = OperaPatches.FindWithHeuristics(settings, pakFileName); if (operaPatch == null) { ColoredConsole.WriteLine(); ColoredConsole.WriteLine("~r~WError:~k~R this Opera version is not supported yet.~N"); return(1); } ColoredConsole.WriteLine(); ColoredConsole.WriteLine("Processing ..."); ColoredConsole.WriteLine(); ColoredConsole.WriteLine("OperaPackHashOffset: ~W0x{0:x8}~N", operaPatch.OperaPakHashOffset); ColoredConsole.WriteLine("SpeeddialLayoutJs: ~W{0}~N", operaPatch.SpeeddialLayoutJs); ColoredConsole.WriteLine("StartPageHtml: ~W{0}~N", operaPatch.StartPageHtml); ColoredConsole.WriteLine("PreinstalledSpeeddialsJs: ~W{0}~N", operaPatch.PreinstalledSpeeddialsJs); ColoredConsole.WriteLine("SpeeddialSuggestionsJs: ~W{0}~N", operaPatch.SpeeddialSuggestionsJs); ColoredConsole.WriteLine("ToolsCss: ~W{0}~N", operaPatch.ToolsCss); ColoredConsole.WriteLine("FilterCss: ~W{0}~N", operaPatch.FilterCss); ColoredConsole.WriteLine(); if (!ColoredConsole.Read("I would like to start patching: ", true)) { return(1); } ColoredConsole.WriteLine(); operaPatch.Apply(settings, pakFileName); result = 0; } catch (Exception ex) { ColoredConsole.WriteLine(); if (ex.InnerException == null) { ColoredConsole.WriteLine("~r~WError:~k~R {0}~N", ex.Message); } else { ColoredConsole.WriteLine("~r~WError:~k~R {0}~N ----> {1}", ex.Message, ex.InnerException.ToString()); } result = 1; } return(result); }
public void Apply(Settings settings, string pakFileName) { string originalPakFileName = pakFileName + BackupExtension; CssPatches cssPatches = settings.CssPatches; PakFile pakFile = new PakFile(); ColoredConsole.WriteLine("Reading ~W{0}~N ...", pakFileName); if (!File.Exists(originalPakFileName)) { File.Copy(pakFileName, originalPakFileName); } else { File.Copy(originalPakFileName, pakFileName, true); } pakFile.Load(pakFileName); const string TEXT_MAX_X_COUNT = " var MAX_X_COUNT = "; const string TEXT_MARGIN_X = " var MARGIN_X = "; const string TEXT_MARGIN_Y = " var MARGIN_Y = "; const string TEXT_DIAL_WIDTH = "SpeeddialObject.DIAL_WIDTH = "; const string TEXT_DIAL_HEIGHT = "SpeeddialObject.DIAL_HEIGHT = "; const string TEXT_THUMBNAIL_URL1 = " \"size=\" + this.DIAL_WIDTH + \"x\" + this.DIAL_HEIGHT +"; const string TEXT_THUMBNAIL_URL2 = " \"size=\" + (({0:F4} * this.DIAL_WIDTH + 0.5) >> 0) + \"x\" + (({0:F4} * this.DIAL_HEIGHT + 0.5) >> 0) +"; const string TEXT_CSS_WIDTH = " width: "; const string TEXT_CSS_HEIGHT = " height: "; const string TEXT_CSS_TOP = " top: "; const string TEXT_CSS_LEFT = " left: "; const string TEXT_CSS_BACKGROUND_POSITION = " background-position: "; const string TEXT_PREINSTALLED_CHECK_URL_FUNCTION = " this.checkURL = function(URL)"; const string TEXT_PREINSTALLED_CHECK_URL_NEXTLINE = " {"; const string TEXT_PREINSTALLED_LAST_LINE = "}).apply(PreinstalledSpeeddials);"; const string TEXT_STYLE = "</style>"; const string TEXT_DIAL_URL = "SpeeddialObject.DIAL_URL + "; const string TEXT_DIAL_RELOAD_URL = "SpeeddialObject.DIAL_RELOAD_URL +"; const string TEXT_ADD_DIAL_URL = "var sdURL = sd_obj.sdURL || SpeeddialObject.DIAL_URL + "; string[] lines = pakFile.GetItem(SpeeddialLayoutJs); for (int n = 0; n < lines.Length; n++) { string line = lines[n]; if (line.StartsWith(TEXT_MAX_X_COUNT)) { lines[n] = TEXT_MAX_X_COUNT + settings.SpeedDial.Columns.ToString() + ";"; } else if (line.StartsWith(TEXT_MARGIN_X)) { lines[n] = TEXT_MARGIN_X + settings.SpeedDial.MarginX.ToString() + ";"; } else if (line.StartsWith(TEXT_MARGIN_Y)) { lines[n] = TEXT_MARGIN_Y + settings.SpeedDial.MarginY.ToString() + ";"; } else if (line.StartsWith(TEXT_DIAL_WIDTH)) { lines[n] = TEXT_DIAL_WIDTH + settings.SpeedDial.ThumbnailWidth.ToString() + ";"; } else if (line.StartsWith(TEXT_DIAL_HEIGHT)) { lines[n] = TEXT_DIAL_HEIGHT + settings.SpeedDial.ThumbnailHeight.ToString() + ";"; } else if (settings.SpeedDial.CropPageForThumbnail && line.StartsWith(TEXT_THUMBNAIL_URL1)) { lines[n] = String.Format(CultureInfo.InvariantCulture, TEXT_THUMBNAIL_URL2, 100.0 / settings.SpeedDial.CropArea); } else if (settings.SpeedDial.AddCustomThumbnails && line.Contains(TEXT_DIAL_URL)) { lines[n] = " PreinstalledSpeeddials.transformURL(this.navigateURL) || (SpeeddialObject.DIAL_URL + encodeURIComponent(this.navigateURL))"; } else if (settings.SpeedDial.AddCustomThumbnails && line.Contains(TEXT_DIAL_RELOAD_URL)) { lines[n] = " PreinstalledSpeeddials.transformURL(this.navigateURL) || (SpeeddialObject.DIAL_RELOAD_URL + encodeURIComponent(this.navigateURL))"; lines[n + 1] = ""; } } pakFile.SetItem(SpeeddialLayoutJs, lines); if (settings.SpeedDial.AddCustomThumbnails) { lines = pakFile.GetItem(SpeeddialSuggestionsJs); for (int n = 0; n < lines.Length; n++) { if (lines[n].Contains(TEXT_ADD_DIAL_URL)) { lines[n] = " var sdURL = sd_obj.sdURL || PreinstalledSpeeddials.transformURL(sd_obj.url) || SpeeddialObject.DIAL_URL + encodeURIComponent(sd_obj.url);"; break; } } pakFile.SetItem(SpeeddialSuggestionsJs, lines); } lines = pakFile.GetItem(StartPageHtml); for (int n = 0; n < lines.Length; n++) { string line = lines[n]; if (line == ".speeddial") { ApplyCssPixelRule(lines, n, TEXT_CSS_WIDTH, settings.SpeedDial.ThumbnailWidth); ApplyCssPixelRule(lines, n, TEXT_CSS_HEIGHT, settings.SpeedDial.ThumbnailHeight); if (settings.SpeedDial.CropPageForThumbnail) { ApplyCssRule(lines, n, TEXT_CSS_BACKGROUND_POSITION, "0% 0%"); } } else if (line == ".dial-thumbnail") { ApplyCssPixelRule(lines, n, TEXT_CSS_WIDTH, (settings.SpeedDial.ThumbnailWidth - 36) / 2); ApplyCssPixelRule(lines, n, TEXT_CSS_HEIGHT, (settings.SpeedDial.ThumbnailHeight - 28) / 2); } else if (line == ".dial-thumbnail:nth-child(2)") { ApplyCssPixelRule(lines, n, TEXT_CSS_LEFT, settings.SpeedDial.ThumbnailWidth / 2); } else if (line == ".dial-thumbnail:nth-child(3)") { ApplyCssPixelRule(lines, n, TEXT_CSS_TOP, settings.SpeedDial.ThumbnailHeight / 2 - 1); } else if (line == ".dial-thumbnail:nth-child(4)") { ApplyCssPixelRule(lines, n, TEXT_CSS_LEFT, settings.SpeedDial.ThumbnailWidth / 2); ApplyCssPixelRule(lines, n, TEXT_CSS_TOP, settings.SpeedDial.ThumbnailHeight / 2 - 1); } else if (line.StartsWith(TEXT_STYLE)) { lines[n] = TEXT_STYLE + cssPatches.Apply("<style>", "</style>", CssPatchFile.StartPageHtml); } } pakFile.SetItem(StartPageHtml, lines); lines = pakFile.GetItem(ToolsCss); lines[lines.Length - 1] = cssPatches.Apply("", "", CssPatchFile.ToolsCss); pakFile.SetItem(ToolsCss, lines); lines = pakFile.GetItem(FilterCss); lines[lines.Length - 1] = cssPatches.Apply("", "", CssPatchFile.FilterCss); pakFile.SetItem(FilterCss, lines); lines = pakFile.GetItem(PreinstalledSpeeddialsJs); for (int n = 0; n < lines.Length; n++) { string line = lines[n]; if (line == TEXT_PREINSTALLED_CHECK_URL_FUNCTION && n < lines.Length - 1 && lines[n + 1].StartsWith(TEXT_PREINSTALLED_CHECK_URL_NEXTLINE)) { lines[n + 1] = TEXT_PREINSTALLED_CHECK_URL_NEXTLINE + (settings.SpeedDial.DisableBuiltInThumbnails ? "return null;" : ""); } else if (settings.SpeedDial.AddCustomThumbnails && line == TEXT_PREINSTALLED_LAST_LINE) { StringBuilder sb = new StringBuilder("var _transformData = { re: null, getRe: function(dict) { return new RegExp(\"^.{4,5}:\\\\/\\\\/(?:[^.]+\\\\.)?(\" + _arr_to_regexp(Object.keys(dict)) + \")(?:\\\\/|$)\"); }, thumbnails: { "); bool f = false; foreach (KeyValuePair <string, string> kvp in settings.SpeedDial.CustomThumbnails) { if (f) { sb.Append(','); } sb.AppendFormat("\"{0}\": \"{1}\"", kvp.Key, kvp.Value); f = true; } sb.Append("} }; this.transformURL = function(URL) { if (!_transformData.re) _transformData.re = _transformData.getRe(_transformData.thumbnails); var match = _transformData.re.exec(URL); return match ? _transformData.thumbnails[match[1]] : null; };"); lines[n] = sb.ToString() + TEXT_PREINSTALLED_LAST_LINE; } } pakFile.SetItem(PreinstalledSpeeddialsJs, lines); ColoredConsole.WriteLine("Writing ~W{0}~N ...", pakFileName); pakFile.Save(pakFileName + ".temp"); File.Delete(pakFileName); File.Move(pakFileName + ".temp", pakFileName); string contentFileName = Path.Combine(Path.GetDirectoryName(pakFileName), "resources\\default_partner_content.json"); string originalContentFileName = contentFileName + BackupExtension; if (!File.Exists(originalContentFileName) && File.Exists(contentFileName)) { File.Copy(contentFileName, originalContentFileName); } else if (File.Exists(originalContentFileName)) { File.Copy(originalContentFileName, contentFileName, true); } if (settings.Search.DeletePartnerSearchEngines) { File.Delete(contentFileName); } if (settings.PatchOperaExe) { string exeFileName = Path.ChangeExtension(pakFileName, ".exe"); string originalExeFileName = exeFileName + OperaPatch.BackupExtension; ColoredConsole.WriteLine("Reading ~W{0}~N ...", exeFileName); if (!File.Exists(originalExeFileName)) { File.Copy(exeFileName, originalExeFileName); } else { File.Copy(originalExeFileName, exeFileName, true); } byte[] exeFile = File.ReadAllBytes(exeFileName); byte[] patched = OperaPatches.GetPakFileHash(pakFileName); byte[] original = OperaPatches.GetPakFileHash(originalPakFileName); if (exeFile.Length < OperaPakHashOffset + patched.Length) { throw new InvalidOperationException("Invalid executable patch: offset error."); } for (int n = 0; n < original.Length; n++) { if (exeFile[OperaPakHashOffset + n] != original[n]) { throw new InvalidOperationException("Invalid executable patch: original data do not match."); } exeFile[OperaPakHashOffset + n] = patched[n]; } if (settings.Search.DeletePartnerSearchEngines) { byte[] search = Encoding.ASCII.GetBytes(SearchSettings.BuiltinUrl); for (int offset = 0; offset < exeFile.Length - search.Length - 1; offset++) { bool found = true; for (int n = 0; found && n < search.Length; n++) { found = exeFile[offset + n] == search[n]; } if (found && exeFile[offset + search.Length] == 0) { byte[] builtin = BuildSearchSettings(SearchSettings.BuiltinUrl, SearchSettings.BuiltinName, SearchSettings.BuiltinKeyword, SearchSettings.BuiltinFavicon, SearchSettings.BuiltinSuggestionUrl); byte[] default1 = BuildSearchSettings(settings.Search.DefaultUrl, settings.Search.DefaultName, settings.Search.DefaultKeyword, settings.Search.DefaultFavicon, settings.Search.DefaultSuggestionUrl); for (int n = 0; found && n < builtin.Length; n++) { found = exeFile[offset + n] == builtin[n]; } if (found) { Array.Copy(default1, 0, exeFile, offset, default1.Length); } else { ColoredConsole.WriteLine("~y~KWarning:~k~Y built-in search engine structure has been changed. You must update SpeedDialPatch.~N"); } } } } ColoredConsole.WriteLine("Writing ~W{0}~N ...", exeFileName); File.WriteAllBytes(exeFileName + ".temp", exeFile); File.Delete(exeFileName); File.Move(exeFileName + ".temp", exeFileName); } }