├── images
├── icon.ico
├── logo.png
├── badges.png
├── logo-v2.png
├── batch-cache.png
├── cache-settings.png
├── config-cache.png
├── launch-video.gif
├── logo-v2-title.png
├── merged-example.png
├── update-check.png
├── plugin-settings.png
├── config-cache-error.png
├── extraction-settings.png
├── select-file-window.png
├── config-cache-warning.png
├── smart-extract-settings.png
└── select-file-window-bigbox.png
├── thirdparty
└── 7-Zip
│ ├── 7z.dll
│ ├── 7z.exe
│ ├── readme.txt
│ └── License.txt
├── src
├── Plugin
│ ├── Resources
│ │ ├── badge.png
│ │ ├── broom.png
│ │ ├── gear.png
│ │ ├── icon.ico
│ │ ├── logo.png
│ │ ├── plus.png
│ │ ├── star.png
│ │ ├── tick.png
│ │ ├── pencil.png
│ │ ├── box--plus.png
│ │ ├── box-zipper.png
│ │ ├── hourglass.png
│ │ ├── icon16x16.png
│ │ ├── icon32x32.png
│ │ ├── joystick.png
│ │ ├── media-cd.png
│ │ ├── media-gc.png
│ │ ├── media-md.png
│ │ ├── media-n64.png
│ │ ├── media-ps1.png
│ │ ├── media-ps2.png
│ │ ├── media-psp.png
│ │ ├── star-blue.png
│ │ ├── cross-script.png
│ │ ├── exclamation.png
│ │ ├── media-ps2-cd.png
│ │ ├── cross-octagon.png
│ │ ├── exclamation-red.png
│ │ ├── icon16x16-play.png
│ │ ├── exclamation-white.png
│ │ ├── arrow-circle-double.png
│ │ ├── Badges
│ │ │ ├── Archive Cached.png
│ │ │ ├── Archive Cached - Neon.png
│ │ │ └── Archive Cached - Simple White.png
│ │ └── folder-horizontal-open.png
│ ├── packages.config
│ ├── MessageBoxBigBox.cs
│ ├── app.config
│ ├── GameBadge.cs
│ ├── SystemMenuItem.cs
│ ├── BatchCacheMenuItem.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── SystemEvents.cs
│ ├── Updater.cs
│ ├── CacheConfigWindow.cs
│ ├── EmulatorPlatformSelectionWindow.cs
│ ├── ArchiveListWindow.cs
│ ├── ArchiveListWindowBigBox.cs
│ ├── MessageBoxBigBox.Designer.cs
│ ├── GameMenuItem.cs
│ ├── MessageBoxBigBox.resx
│ ├── LaunchBoxSettings.cs
│ ├── ArchiveListWindowBigBox.Designer.cs
│ ├── EmulatorPlatformSelectionWindow.Designer.cs
│ ├── PluginUtils.cs
│ ├── Plugin.csproj
│ └── ArchiveListWindow.Designer.cs
├── ArchiveCacheManager
│ ├── icon.ico
│ ├── App.config
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── ArchiveCacheManager.csproj
│ └── Program.cs
├── Core
│ ├── packages.config
│ ├── MatchSettings.cs
│ ├── Utils.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Extractors
│ │ ├── DolphinTool.cs
│ │ ├── Robocopy.cs
│ │ ├── Extractor.cs
│ │ ├── Chdman.cs
│ │ ├── ExtractXiso.cs
│ │ └── Zip.cs
│ ├── GameIndex.cs
│ ├── Logger.cs
│ ├── Core.csproj
│ ├── FastWildcard.cs
│ ├── DiskUtils.cs
│ └── ProcessUtils.cs
└── ArchiveCacheManager.sln
├── HISTORY.md
└── .gitignore
/images/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/images/icon.ico
--------------------------------------------------------------------------------
/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/images/logo.png
--------------------------------------------------------------------------------
/images/badges.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/images/badges.png
--------------------------------------------------------------------------------
/images/logo-v2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/images/logo-v2.png
--------------------------------------------------------------------------------
/images/batch-cache.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/images/batch-cache.png
--------------------------------------------------------------------------------
/images/cache-settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/images/cache-settings.png
--------------------------------------------------------------------------------
/images/config-cache.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/images/config-cache.png
--------------------------------------------------------------------------------
/images/launch-video.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/images/launch-video.gif
--------------------------------------------------------------------------------
/images/logo-v2-title.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/images/logo-v2-title.png
--------------------------------------------------------------------------------
/images/merged-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/images/merged-example.png
--------------------------------------------------------------------------------
/images/update-check.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/images/update-check.png
--------------------------------------------------------------------------------
/thirdparty/7-Zip/7z.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/thirdparty/7-Zip/7z.dll
--------------------------------------------------------------------------------
/thirdparty/7-Zip/7z.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/thirdparty/7-Zip/7z.exe
--------------------------------------------------------------------------------
/images/plugin-settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/images/plugin-settings.png
--------------------------------------------------------------------------------
/images/config-cache-error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/images/config-cache-error.png
--------------------------------------------------------------------------------
/images/extraction-settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/images/extraction-settings.png
--------------------------------------------------------------------------------
/images/select-file-window.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/images/select-file-window.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/badge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/badge.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/broom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/broom.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/gear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/gear.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/icon.ico
--------------------------------------------------------------------------------
/src/Plugin/Resources/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/logo.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/plus.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/star.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/star.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/tick.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/tick.png
--------------------------------------------------------------------------------
/images/config-cache-warning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/images/config-cache-warning.png
--------------------------------------------------------------------------------
/src/ArchiveCacheManager/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/ArchiveCacheManager/icon.ico
--------------------------------------------------------------------------------
/src/Plugin/Resources/pencil.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/pencil.png
--------------------------------------------------------------------------------
/images/smart-extract-settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/images/smart-extract-settings.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/box--plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/box--plus.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/box-zipper.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/box-zipper.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/hourglass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/hourglass.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/icon16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/icon16x16.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/icon32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/icon32x32.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/joystick.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/joystick.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/media-cd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/media-cd.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/media-gc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/media-gc.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/media-md.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/media-md.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/media-n64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/media-n64.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/media-ps1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/media-ps1.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/media-ps2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/media-ps2.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/media-psp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/media-psp.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/star-blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/star-blue.png
--------------------------------------------------------------------------------
/images/select-file-window-bigbox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/images/select-file-window-bigbox.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/cross-script.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/cross-script.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/exclamation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/exclamation.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/media-ps2-cd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/media-ps2-cd.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/cross-octagon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/cross-octagon.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/exclamation-red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/exclamation-red.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/icon16x16-play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/icon16x16-play.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/exclamation-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/exclamation-white.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/arrow-circle-double.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/arrow-circle-double.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/Badges/Archive Cached.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/Badges/Archive Cached.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/folder-horizontal-open.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/folder-horizontal-open.png
--------------------------------------------------------------------------------
/src/Core/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/Plugin/Resources/Badges/Archive Cached - Neon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/Badges/Archive Cached - Neon.png
--------------------------------------------------------------------------------
/src/Plugin/Resources/Badges/Archive Cached - Simple White.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraganator/archive-cache-manager/HEAD/src/Plugin/Resources/Badges/Archive Cached - Simple White.png
--------------------------------------------------------------------------------
/src/ArchiveCacheManager/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/Plugin/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/Core/MatchSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FastWildcard
4 | {
5 | public class MatchSettings
6 | {
7 | private const StringComparison DefaultStringComparison = StringComparison.Ordinal;
8 |
9 | ///
10 | /// Case rules to use when comparing matching characters.
11 | /// Defaults to .
12 | ///
13 | public StringComparison StringComparison { get; set; }
14 |
15 | public MatchSettings()
16 | {
17 | StringComparison = DefaultStringComparison;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Plugin/MessageBoxBigBox.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Reflection;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 | using System.Windows.Forms;
11 |
12 | namespace ArchiveCacheManager
13 | {
14 | public partial class MessageBoxBigBox : Form
15 | {
16 | public MessageBoxBigBox(string text)
17 | {
18 | InitializeComponent();
19 |
20 | UserInterface.ScaleControlFont(message, 96.0f / message.DeviceDpi);
21 |
22 | message.Text = text;
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Plugin/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/Plugin/GameBadge.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.IO;
8 | using Unbroken.LaunchBox.Plugins.Data;
9 |
10 | namespace ArchiveCacheManager
11 | {
12 | class GameBadge : IGameBadge
13 | {
14 | private int mIndex = 99;
15 |
16 | public string Name => "Archive Cached";
17 | public string UniqueId => "Archive Cached";
18 | public Image DefaultIcon => Resources.badge;
19 | public int Index
20 | {
21 | get => mIndex;
22 | set => mIndex = value;
23 | }
24 |
25 | public bool GetAppliesToGame(IGame game)
26 | {
27 | return File.Exists(PathUtils.GetArchiveCacheGameInfoPath(PathUtils.ArchiveCachePath(PathUtils.GetAbsolutePath(game.ApplicationPath))));
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Core/Utils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ArchiveCacheManager
8 | {
9 | static class Utils
10 | {
11 | ///
12 | /// Convert the provided object into an array with the object as its single item.
13 | /// If the object is null, the resulting array will be null (NOT an array with a single null element)
14 | ///
15 | /// The type of the object that will be provided and contained in the returned array.
16 | /// The item which will be contained in the return array as its single item.
17 | /// An array with as its single item.
18 | public static T[] ToSingleArray(this T singleElement) => singleElement != null ? new[] { singleElement } : null;
19 |
20 | public static string[] SplitExtensions(string extensions)
21 | {
22 | return extensions.ToLower().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(ex => ex.Trim()).ToArray();
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Plugin/SystemMenuItem.cs:
--------------------------------------------------------------------------------
1 | using System.Drawing;
2 | using Unbroken.LaunchBox.Plugins;
3 | using System.Windows.Forms;
4 | using System.Windows.Interop;
5 |
6 | namespace ArchiveCacheManager
7 | {
8 | public class SystemMenuItem : ISystemMenuItemPlugin
9 | {
10 | public string Caption => "Archive Cache Manager...";
11 | public Image IconImage => Resources.icon16x16;
12 | public bool ShowInLaunchBox => true;
13 | public bool ShowInBigBox => false;
14 | public bool AllowInBigBoxWhenLocked => false;
15 |
16 | public void OnSelected()
17 | {
18 | //ConfigWindow window = new ConfigWindow();
19 | NewConfigWindow window = new NewConfigWindow();
20 | NativeWindow parent = new NativeWindow();
21 |
22 | // Glue between the main app window (WPF) and this window (WinForms)
23 | parent.AssignHandle(new WindowInteropHelper(System.Windows.Application.Current.MainWindow).Handle);
24 | window.ShowDialog(parent);
25 |
26 | if (window.RefreshLaunchBox && !PluginHelper.StateManager.IsBigBox)
27 | {
28 | PluginHelper.LaunchBoxMainViewModel.RefreshData();
29 | }
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Core/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Archive Cache Manager Core")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Archive Cache Manager")]
13 | [assembly: AssemblyCopyright("Copyright © 2023")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("035823e0-c80b-49bf-9fad-9c65ea45e3a9")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("2.16.0.0")]
36 | [assembly: AssemblyFileVersion("2.16.0.0")]
37 |
--------------------------------------------------------------------------------
/src/ArchiveCacheManager/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Archive Cache Manager")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Archive Cache Manager")]
13 | [assembly: AssemblyCopyright("Copyright © 2023")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("687f96d0-dfb8-4a53-bf23-aa02bd7658ec")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("2.16.0.0")]
36 | [assembly: AssemblyFileVersion("2.16.0.0")]
37 |
--------------------------------------------------------------------------------
/src/Plugin/BatchCacheMenuItem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Windows.Forms;
8 | using System.Windows.Interop;
9 | using Unbroken.LaunchBox.Plugins;
10 | using Unbroken.LaunchBox.Plugins.Data;
11 |
12 | namespace ArchiveCacheManager
13 | {
14 | class BatchCacheMenuItem : IGameMenuItemPlugin
15 | {
16 | public bool SupportsMultipleGames => true;
17 | public string Caption => "Batch Cache Games...";
18 | public Image IconImage => Resources.icon16x16;
19 | public bool ShowInLaunchBox => true;
20 | public bool ShowInBigBox => false;
21 | public bool GetIsValidForGame(IGame selectedGame) => true;
22 | public bool GetIsValidForGames(IGame[] selectedGames) => true;
23 | public void OnSelected(IGame selectedGame) => OnSelected(new IGame[] { selectedGame });
24 |
25 | public void OnSelected(IGame[] selectedGames)
26 | {
27 | BatchCacheWindow window = new BatchCacheWindow(selectedGames);
28 | NativeWindow parent = new NativeWindow();
29 |
30 | // Glue between the main app window (WPF) and this window (WinForms)
31 | parent.AssignHandle(new WindowInteropHelper(System.Windows.Application.Current.MainWindow).Handle);
32 | window.ShowDialog(parent);
33 |
34 | if (window.RefreshLaunchBox && !PluginHelper.StateManager.IsBigBox)
35 | {
36 | PluginHelper.LaunchBoxMainViewModel.RefreshData();
37 | }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Plugin/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | [assembly: System.Windows.ThemeInfo(System.Windows.ResourceDictionaryLocation.None, System.Windows.ResourceDictionaryLocation.SourceAssembly)]
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | [assembly: AssemblyTitle("Archive Cache Manager Plugin")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("")]
14 | [assembly: AssemblyProduct("Archive Cache Manager")]
15 | [assembly: AssemblyCopyright("Copyright © 2023")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | [assembly: ComVisible(false)]
23 |
24 | // The following GUID is for the ID of the typelib if this project is exposed to COM
25 | [assembly: Guid("205f6c26-c727-4171-a760-3599aa2d00d2")]
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | // [assembly: AssemblyVersion("1.0.*")]
37 | [assembly: AssemblyVersion("2.16.0.0")]
38 | [assembly: AssemblyFileVersion("2.16.0.0")]
39 |
--------------------------------------------------------------------------------
/thirdparty/7-Zip/readme.txt:
--------------------------------------------------------------------------------
1 | 7-Zip 21.07
2 | -----------
3 |
4 | 7-Zip is a file archiver for Windows.
5 |
6 | 7-Zip Copyright (C) 1999-2021 Igor Pavlov.
7 |
8 | The main features of 7-Zip:
9 |
10 | - High compression ratio in the new 7z format
11 | - Supported formats:
12 | - Packing / unpacking: 7z, XZ, BZIP2, GZIP, TAR, ZIP and WIM.
13 | - Unpacking only: AR, ARJ, Base64, CAB, CHM, CPIO, CramFS, DMG, EXT, FAT, GPT, HFS,
14 | IHEX, ISO, LZH, LZMA, MBR, MSI, NSIS, NTFS, QCOW2, RAR,
15 | RPM, SquashFS, UDF, UEFI, VDI, VHD, VHDX, VMDK, XAR and Z.
16 | - Fast compression and decompression
17 | - Self-extracting capability for 7z format
18 | - Strong AES-256 encryption in 7z and ZIP formats
19 | - Integration with Windows Shell
20 | - Powerful File Manager
21 | - Powerful command line version
22 | - Localizations for 90 languages
23 |
24 |
25 | 7-Zip is free software distributed under the GNU LGPL (except for unRar code).
26 | Read License.txt for more information about license.
27 |
28 |
29 | This distribution package contains the following files:
30 |
31 | 7zFM.exe - 7-Zip File Manager
32 | 7-zip.dll - Plugin for Windows Shell
33 | 7-zip32.dll - Plugin for Windows Shell (32-bit plugin for 64-bit system)
34 | 7zg.exe - GUI module
35 | 7z.exe - Command line version
36 | 7z.dll - 7-Zip engine module
37 | 7z.sfx - SFX module (Windows version)
38 | 7zCon.sfx - SFX module (Console version)
39 |
40 | License.txt - License information
41 | readme.txt - This file
42 | History.txt - History of 7-Zip
43 | 7-zip.chm - User's Manual in HTML Help format
44 | descript.ion - Description for files
45 |
46 | Lang\en.ttt - English (base) localization file
47 | Lang\*.txt - Localization files
48 |
49 |
50 | ---
51 | End of document
52 |
--------------------------------------------------------------------------------
/src/Core/Extractors/DolphinTool.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.IO;
7 | using System.Text.RegularExpressions;
8 |
9 | namespace ArchiveCacheManager
10 | {
11 | public class DolphinTool : Extractor
12 | {
13 | string executablePath = Path.Combine(PathUtils.GetExtractorRootPath(), "DolphinTool.exe");
14 |
15 | public DolphinTool()
16 | {
17 |
18 | }
19 |
20 | public static bool SupportedType(string archivePath)
21 | {
22 | return PathUtils.HasExtension(archivePath, new string[] { ".rvz", ".wia", ".gcz" });
23 | }
24 |
25 | public override bool Extract(string archivePath, string cachePath, string[] includeList = null, string[] excludeList = null)
26 | {
27 | string args = string.Format("convert -i \"{0}\" -o \"{1}\" -f iso", archivePath, Path.Combine(cachePath, Path.GetFileNameWithoutExtension(archivePath) + ".iso"));
28 |
29 | // chdman reports the progress status on stderr, not stdout
30 | (string stdout, string stderr, int exitCode) = ProcessUtils.RunProcess(executablePath, args);
31 |
32 | if (exitCode != 0)
33 | {
34 | Logger.Log(string.Format("DolphinTool returned exit code {0} with error output:\r\n{1}", exitCode, stderr));
35 | Environment.ExitCode = exitCode;
36 | }
37 |
38 | return exitCode == 0;
39 | }
40 |
41 | public override long GetSize(string archivePath, string fileInArchive = null)
42 | {
43 | return DiskUtils.GetFileSize(archivePath);
44 | }
45 |
46 | public override string[] List(string archivePath)
47 | {
48 | return string.Format("{0}.iso", Path.GetFileNameWithoutExtension(archivePath)).ToSingleArray();
49 | }
50 |
51 | public override string Name()
52 | {
53 | return "DolphinTool";
54 | }
55 |
56 | public override string GetExtractorPath()
57 | {
58 | return executablePath;
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/ArchiveCacheManager.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.31005.135
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Plugin", "Plugin\Plugin.csproj", "{205F6C26-C727-4171-A760-3599AA2D00D2}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", "{035823E0-C80B-49BF-9FAD-9C65EA45E3A9}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArchiveCacheManager", "ArchiveCacheManager\ArchiveCacheManager.csproj", "{687F96D0-DFB8-4A53-BF23-AA02BD7658EC}"
11 | ProjectSection(ProjectDependencies) = postProject
12 | {205F6C26-C727-4171-A760-3599AA2D00D2} = {205F6C26-C727-4171-A760-3599AA2D00D2}
13 | EndProjectSection
14 | EndProject
15 | Global
16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
17 | Debug|Any CPU = Debug|Any CPU
18 | Release|Any CPU = Release|Any CPU
19 | EndGlobalSection
20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
21 | {205F6C26-C727-4171-A760-3599AA2D00D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
22 | {205F6C26-C727-4171-A760-3599AA2D00D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
23 | {205F6C26-C727-4171-A760-3599AA2D00D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
24 | {205F6C26-C727-4171-A760-3599AA2D00D2}.Release|Any CPU.Build.0 = Release|Any CPU
25 | {035823E0-C80B-49BF-9FAD-9C65EA45E3A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26 | {035823E0-C80B-49BF-9FAD-9C65EA45E3A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
27 | {035823E0-C80B-49BF-9FAD-9C65EA45E3A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
28 | {035823E0-C80B-49BF-9FAD-9C65EA45E3A9}.Release|Any CPU.Build.0 = Release|Any CPU
29 | {687F96D0-DFB8-4A53-BF23-AA02BD7658EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
30 | {687F96D0-DFB8-4A53-BF23-AA02BD7658EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
31 | {687F96D0-DFB8-4A53-BF23-AA02BD7658EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
32 | {687F96D0-DFB8-4A53-BF23-AA02BD7658EC}.Release|Any CPU.Build.0 = Release|Any CPU
33 | EndGlobalSection
34 | GlobalSection(SolutionProperties) = preSolution
35 | HideSolutionNode = FALSE
36 | EndGlobalSection
37 | GlobalSection(ExtensibilityGlobals) = postSolution
38 | SolutionGuid = {B5C39C6A-A1EF-4C32-B4F0-0F2BCAE39F8F}
39 | EndGlobalSection
40 | EndGlobal
41 |
--------------------------------------------------------------------------------
/src/Plugin/SystemEvents.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using Unbroken.LaunchBox.Plugins;
3 |
4 | namespace ArchiveCacheManager
5 | {
6 | class SystemEvents : ISystemEventsPlugin
7 | {
8 | public void OnEventRaised(string eventType)
9 | {
10 | if (eventType == "PluginInitialized")
11 | {
12 | #if DEBUG
13 | Debugger.Launch();
14 | #endif
15 | Logger.Init();
16 | Logger.Log("-------- PLUGIN INITIALIZED --------");
17 | Logger.Log(string.Format("Archive Cache Manager plugin initialized ({0}).", CacheManager.VersionString));
18 | // Restore 7z in event Archive Cache Manager files are still in ThirdParty\7-Zip (caused by crash, etc)
19 | GameLaunching.Restore7z();
20 | // Remove any invalid entries from the cache (from failed or aborted launches, or game.ini changes)
21 | CacheManager.VerifyCacheIntegrity();
22 | }
23 | // Only perform the actions below in LaunchBox
24 | else if (eventType == "LaunchBoxStartupCompleted")
25 | {
26 | // Restore any overridden settings if LaunchBox closed before they could be restored on normal game launch
27 | LaunchBoxDataBackup.RestoreAllSettingsDelay(1000);
28 |
29 | if (Config.UpdateCheck == true)
30 | {
31 | Updater.CheckForUpdate(2000);
32 | }
33 | // UpdateCheck will be null if the option has never been set before. Prompt the user to enable or disable update checks.
34 | else if (Config.UpdateCheck == null)
35 | {
36 | Updater.EnableUpdateCheckPrompt(2000);
37 | }
38 | }
39 | else if (eventType == "LaunchBoxShutdownBeginning" || eventType == "BigBoxShutdownBeginning")
40 | {
41 | Logger.Log("LaunchBox / BigBox shutdown.");
42 | // Restore 7z in event Archive Cache Manager files are still in ThirdParty\7-Zip (caused by crash, etc)
43 | GameLaunching.Restore7z();
44 | // Restore any overridden settings if LaunchBox closed before they could be restored on normal game launch
45 | LaunchBoxDataBackup.RestoreAllSettings();
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Core/GameIndex.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.IO;
7 | using IniParser;
8 | using IniParser.Model;
9 |
10 | namespace ArchiveCacheManager
11 | {
12 | public class GameIndex
13 | {
14 | private readonly string SelectedFile = "SelectedFile";
15 |
16 | private static IniData mGameIndex = null;
17 |
18 | static GameIndex()
19 | {
20 | Load();
21 | }
22 |
23 | public static void Load()
24 | {
25 | string gameIndexPath = PathUtils.GetPluginGameIndexPath();
26 | mGameIndex = null;
27 |
28 | if (File.Exists(gameIndexPath))
29 | {
30 | var parser = new FileIniDataParser();
31 | mGameIndex = new IniData();
32 |
33 | try
34 | {
35 | mGameIndex = parser.ReadFile(gameIndexPath);
36 | }
37 | catch (Exception e)
38 | {
39 | Logger.Log(string.Format("Error parsing game index file from {0}. Deleting invalid file.", gameIndexPath));
40 | Logger.Log(e.ToString(), Logger.LogLevel.Exception);
41 | File.Delete(gameIndexPath);
42 | mGameIndex = null;
43 | }
44 | }
45 | }
46 |
47 | public static void Save()
48 | {
49 | string gameIndexPath = PathUtils.GetPluginGameIndexPath();
50 |
51 | if (mGameIndex != null)
52 | {
53 | var parser = new FileIniDataParser();
54 |
55 | try
56 | {
57 | parser.WriteFile(gameIndexPath, mGameIndex);
58 | }
59 | catch (Exception e)
60 | {
61 | Logger.Log(string.Format("Error saving game index file to {0}.", gameIndexPath));
62 | Logger.Log(e.ToString(), Logger.LogLevel.Exception);
63 | }
64 | }
65 | }
66 |
67 | public static string GetSelectedFile(string gameId)
68 | {
69 | string selectedFile = string.Empty;
70 |
71 | if (mGameIndex != null && mGameIndex.Sections.ContainsSection(gameId))
72 | {
73 | selectedFile = mGameIndex[gameId][nameof(SelectedFile)] ?? string.Empty;
74 | }
75 |
76 | return selectedFile;
77 | }
78 |
79 | public static void SetSelectedFile(string gameId, string selectedFile)
80 | {
81 | if (mGameIndex == null)
82 | {
83 | mGameIndex = new IniData();
84 | }
85 |
86 | mGameIndex[gameId][nameof(SelectedFile)] = selectedFile;
87 |
88 | Save();
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/Core/Extractors/Robocopy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.IO;
7 | using System.Text.RegularExpressions;
8 |
9 | namespace ArchiveCacheManager
10 | {
11 | public class Robocopy : Extractor
12 | {
13 | private long? archiveSize;
14 | private string archiveSizePath;
15 |
16 | public Robocopy()
17 | {
18 | archiveSize = null;
19 | archiveSizePath = string.Empty;
20 | }
21 |
22 | public override bool Extract(string archivePath, string cachePath, string[] includeList = null, string[] excludeList = null)
23 | {
24 | // If the file is less than 50MB, the overhead of calling Robocopy isn't worth it. Instead just use File.Copy().
25 | if (GetSize(archivePath) > 52_428_800)
26 | {
27 | string args = string.Format("/c robocopy \"{0}\" \"{1}\" \"{2}\"", Path.GetDirectoryName(archivePath), cachePath, Path.GetFileName(archivePath));
28 |
29 | (string stdout, string stderr, int exitCode) = ProcessUtils.RunProcess("cmd.exe", args, true, ExtractionProgress, true);
30 |
31 | if (exitCode >= 8)
32 | {
33 | Logger.Log(string.Format("Robocopy returned exit code {0} with error output:\r\n{1}", exitCode, stdout));
34 | Environment.ExitCode = exitCode;
35 | }
36 |
37 | return exitCode < 8;
38 | }
39 | else
40 | {
41 | try
42 | {
43 | File.Copy(archivePath, Path.Combine(cachePath, Path.GetFileName(archivePath)), true);
44 | return true;
45 | }
46 | catch (Exception e)
47 | {
48 | Logger.Log($"File copy error: {e.ToString()}");
49 | Console.Out.WriteLine(e.Message);
50 | Environment.ExitCode = 1;
51 | }
52 | }
53 |
54 | return false;
55 | }
56 |
57 | public override long GetSize(string archivePath, string fileInArchive = null)
58 | {
59 | if (!Equals(archivePath, archiveSizePath) || archiveSize == null)
60 | {
61 | archiveSizePath = archivePath;
62 | archiveSize = DiskUtils.GetFileSize(archivePath);
63 | }
64 |
65 | return (long)archiveSize;
66 | }
67 |
68 | public override string[] List(string archivePath)
69 | {
70 | return Path.GetFileName(archivePath).ToSingleArray();
71 | }
72 |
73 | public override string Name()
74 | {
75 | return "File Copy";
76 | }
77 |
78 | public override string GetExtractorPath()
79 | {
80 | return null;
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/Core/Logger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace ArchiveCacheManager
5 | {
6 | ///
7 | /// Helper class to log plugin status and errors.
8 | ///
9 | public class Logger
10 | {
11 | public enum LogLevel
12 | {
13 | None = 0,
14 | Exception,
15 | Debug,
16 | Info
17 | };
18 |
19 | ///
20 | /// Initialise the log file. Will delete the previous log file if it exists.
21 | ///
22 | public static void Init()
23 | {
24 | try
25 | {
26 | string logPath = PathUtils.GetLogPath();
27 |
28 | if (!Directory.Exists(logPath))
29 | {
30 | Directory.CreateDirectory(logPath);
31 | }
32 | else
33 | {
34 | string[] logs = Directory.GetFiles(PathUtils.GetLogPath(), "*.log");
35 |
36 | Array.Sort(logs);
37 |
38 | for (int i = 0; i < logs.Length - 10; i++)
39 | {
40 | File.Delete(logs[i]);
41 | }
42 | }
43 |
44 | string oldLogFilePath = Path.Combine(PathUtils.GetPluginRootPath(), "events.log");
45 |
46 | if (File.Exists(oldLogFilePath))
47 | {
48 | File.Delete(oldLogFilePath);
49 | }
50 | }
51 | catch (IOException)
52 | {
53 | }
54 | }
55 |
56 | ///
57 | /// Write a message to the log file. All entries will be timestamped.
58 | ///
59 | /// The message to log.
60 | /// The severity of the log entry. Default is LogLevel.Info.
61 | public static void Log(string message, LogLevel logLevel = LogLevel.Info)
62 | {
63 | StreamWriter writer = null;
64 |
65 | try
66 | {
67 | writer = new StreamWriter(PathUtils.GetLogFilePath(), true);
68 | writer.Write(string.Format("{0} - {1}\r\n", GetDateTime(), message));
69 | }
70 | catch (IOException)
71 | {
72 |
73 | }
74 | finally
75 | {
76 | if (writer != null)
77 | {
78 | writer.Close();
79 | }
80 | }
81 | }
82 |
83 | ///
84 | /// Returns the current date and time in YYYY-MM-DD HH:MM:SS format.
85 | ///
86 | /// The current date and time in YYYY-MM-DD HH:MM:SS format.
87 | private static string GetDateTime()
88 | {
89 | DateTime dt = DateTime.Now;
90 | return string.Format("{0:0000}-{1:00}-{2:00} {3:00}:{4:00}:{5:00}", dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second);
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/Plugin/Updater.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows.Forms;
7 | using Octokit;
8 |
9 | namespace ArchiveCacheManager
10 | {
11 | class Updater
12 | {
13 | public static async void CheckForUpdate(int delay = 0)
14 | {
15 | await Task.Delay(delay);
16 |
17 | try
18 | {
19 | var client = new GitHubClient(new ProductHeaderValue("archive-cache-manager"));
20 | var latestRelease = await client.Repository.Release.GetLatest("fraganator", "archive-cache-manager");
21 | string latestReleaseString = latestRelease.TagName.Replace("v", "");
22 | Version latestVersion = new Version(latestReleaseString);
23 |
24 | if (latestVersion > CacheManager.Version)
25 | {
26 | Logger.Log(string.Format("Update check found new version: {0}", latestRelease.TagName));
27 |
28 | if (string.IsNullOrEmpty(Config.SkipUpdate) || latestVersion > new Version(Config.SkipUpdate))
29 | {
30 | var result = FlexibleMessageBox.Show(string.Format("Version {0} of Archive Cache Manager is now available for download. New features include:\r\n\r\n{1}\r\n", latestReleaseString, latestRelease.Body),
31 | "Update Check", MessageBoxButtons.YesNoCancel, Resources.icon32x32, MessageBoxDefaultButton.Button1,
32 | "View Homepage", "Skip This Version", "Remind Me Later");
33 | if (result == DialogResult.Yes)
34 | {
35 | PluginUtils.OpenURL("https://forums.launchbox-app.com/files/file/234-archive-cache-manager/");
36 | }
37 | else if (result == DialogResult.No)
38 | {
39 | Config.SkipUpdate = latestVersion.ToString();
40 | Config.Save();
41 | }
42 | }
43 | }
44 | else
45 | {
46 | Logger.Log("Update check found latest version installed.");
47 | }
48 | }
49 | catch (Exception e)
50 | {
51 | Logger.Log(string.Format("Update check failed: {0}", e.ToString()));
52 | }
53 | }
54 |
55 | public static async void EnableUpdateCheckPrompt(int delay = 0)
56 | {
57 | await Task.Delay(delay);
58 |
59 | var result = FlexibleMessageBox.Show("Archive Cache Manager can notify you when a new update is available.\r\nNothing will be automatically downloaded or installed.\r\n\r\nEnable update check on startup?",
60 | "Enable update check?", MessageBoxButtons.YesNo, Resources.icon32x32, MessageBoxDefaultButton.Button2);
61 |
62 | Config.UpdateCheck = (result == DialogResult.Yes);
63 | Config.Save();
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/Plugin/CacheConfigWindow.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 | using System.Windows.Forms;
11 |
12 | namespace ArchiveCacheManager
13 | {
14 | public partial class CacheConfigWindow : Form
15 | {
16 | public CacheConfigWindow()
17 | {
18 | InitializeComponent();
19 |
20 | cachePath.Text = Config.CachePath;
21 | cacheSize.Value = Config.CacheSize;
22 | minArchiveSize.Value = Config.MinArchiveSize;
23 |
24 | updateEnabledState();
25 |
26 | UserInterface.ApplyTheme(this);
27 | }
28 |
29 | private void updateEnabledState()
30 | {
31 | okButton.Enabled = (cachePath.Text != string.Empty);
32 | }
33 |
34 | private void okButton_Click(object sender, EventArgs e)
35 | {
36 | if (!PathUtils.IsPathSafe(cachePath.Text))
37 | {
38 | UserInterface.ErrorDialog($"ERROR! The cache path can not be set to {Path.GetFullPath(cachePath.Text)}.\r\nPlease change the cache path.", this);
39 | return;
40 | }
41 |
42 | try
43 | {
44 | // Don't warn if path is unchanged, as it probably already has files in it.
45 | if (!PathUtils.ComparePaths(cachePath.Text, Config.CachePath) &&
46 | (Directory.EnumerateFiles(cachePath.Text, "*", SearchOption.AllDirectories).Any() || Directory.EnumerateDirectories(cachePath.Text).Any()))
47 | {
48 | DialogResult result = FlexibleMessageBox.Show(this, "WARNING! The selected cache path already contains files. These files WILL be deleted when the cache is cleaned. Continue?", "Warning!", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
49 |
50 | if (result == DialogResult.No)
51 | {
52 | return;
53 | }
54 | }
55 | }
56 | catch (DirectoryNotFoundException)
57 | {
58 | }
59 |
60 | Config.CachePath = cachePath.Text;
61 | Config.CacheSize = Convert.ToInt64(cacheSize.Value);
62 | Config.MinArchiveSize = Convert.ToInt64(minArchiveSize.Value);
63 |
64 | this.DialogResult = DialogResult.OK;
65 | this.Close();
66 | }
67 |
68 | private void cachePath_TextChanged(object sender, EventArgs e)
69 | {
70 | updateEnabledState();
71 | }
72 |
73 | private void cachePathBrowseButton_Click(object sender, EventArgs e)
74 | {
75 | FolderBrowserDialog dialog = new FolderBrowserDialog();
76 | string browsePath = PathUtils.CachePath(cachePath.Text);
77 |
78 | dialog.SelectedPath = Directory.Exists(browsePath) ? browsePath : PathUtils.GetLaunchBoxRootPath();
79 | dialog.ShowNewFolderButton = true;
80 |
81 | if (dialog.ShowDialog() == DialogResult.OK)
82 | {
83 | cachePath.Text = PathUtils.GetRelativePath(PathUtils.GetLaunchBoxRootPath(), dialog.SelectedPath);
84 | }
85 |
86 | updateEnabledState();
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/Core/Extractors/Extractor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Text.RegularExpressions;
8 |
9 | namespace ArchiveCacheManager
10 | {
11 | public abstract class Extractor
12 | {
13 | private static int mProgressDivisor = 1;
14 | private static int mProgressOffset = 0;
15 | // This regex handles 7z, robocopy, and chdman.
16 | // Other extractors may be different, so set ProgressRegex accordingly.
17 | private static string mProgressRegex = "(\\d+\\.?\\d*)%(.*)";
18 |
19 | public int ProgressDivisor
20 | {
21 | get => mProgressDivisor;
22 | set => mProgressDivisor = Math.Max(value, 1);
23 | }
24 |
25 | public int ProgressOffset
26 | {
27 | get => mProgressOffset;
28 | set => mProgressOffset = Math.Max(value, 0);
29 | }
30 |
31 | protected string ProgressRegex
32 | {
33 | get => mProgressRegex;
34 | set => mProgressRegex = value;
35 | }
36 |
37 | public static string ExtractionProgress(string stdout)
38 | {
39 | string progress = stdout;
40 |
41 | if (stdout != null)
42 | {
43 | try
44 | {
45 | Match match = Regex.Match(stdout, mProgressRegex);
46 | if (match.Success)
47 | {
48 | progress = string.Format("{0,3}% - extracting", (int)(double.Parse(match.Groups[1].Value) / mProgressDivisor) + mProgressOffset);
49 | }
50 | }
51 | catch (Exception)
52 | {
53 |
54 | }
55 | }
56 |
57 | return progress;
58 | }
59 |
60 | ///
61 | /// Name of the extractor, used for informational purposes.
62 | ///
63 | /// Name of the extractor.
64 | public abstract string Name();
65 |
66 | ///
67 | /// Get the size of specified archive after extraction.
68 | ///
69 | ///
70 | /// ///
71 | /// The extracted size of the archive in bytes.
72 | public abstract long GetSize(string archivePath, string fileInArchive = null);
73 |
74 | ///
75 | /// Run the extract command on the specified archive. Console output should be redirected to this app's console so
76 | /// LaunchBox has access to the extraction progress.
77 | ///
78 | ///
79 | /// True on successful extraction, False otherwise.
80 | public abstract bool Extract(string archivePath, string cachePath, string[] includeList = null, string[] excludeList = null);
81 |
82 | ///
83 | /// Get a file list for the specified archive.
84 | ///
85 | /// Archive to list.
86 | /// The list of files in an archive.
87 | public abstract string[] List(string archivePath);
88 |
89 | public abstract string GetExtractorPath();
90 | }
91 | }
--------------------------------------------------------------------------------
/src/Plugin/EmulatorPlatformSelectionWindow.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 | using Unbroken.LaunchBox.Plugins;
11 |
12 | namespace ArchiveCacheManager
13 | {
14 | public partial class EmulatorPlatformSelectionWindow : Form
15 | {
16 | public string Emulator = "";
17 | public string Platform = "";
18 |
19 | public EmulatorPlatformSelectionWindow(string emulator = null, string platform = null)
20 | {
21 | InitializeComponent();
22 |
23 | emulatorComboBox.Items.Clear();
24 | platformComboBox.Items.Clear();
25 |
26 | if (emulator != null && platform != null)
27 | {
28 | emulatorComboBox.Items.Add(emulator);
29 | platformComboBox.Items.Add(platform);
30 | emulatorComboBox.SelectedIndex = 0;
31 | platformComboBox.SelectedIndex = 0;
32 | }
33 | else
34 | {
35 | emulatorComboBox.Items.AddRange(PluginHelper.DataManager.GetAllEmulators().Select(emu => emu.Title).ToArray());
36 | if (emulatorComboBox.Items.Count > 0)
37 | {
38 | emulatorComboBox.SelectedIndex = 0;
39 | populatePlatforms(emulatorComboBox.SelectedItem.ToString());
40 | }
41 | }
42 |
43 | updateEnabledState();
44 |
45 | UserInterface.ApplyTheme(this);
46 | }
47 |
48 | private void populatePlatforms(string emulatorName)
49 | {
50 | platformComboBox.Items.Clear();
51 |
52 | var platforms = PluginHelper.DataManager.GetAllEmulators().Single(emulator => emulator.Title == emulatorName).GetAllEmulatorPlatforms();
53 | platformComboBox.Items.AddRange(platforms.Select(platform => platform.Platform).ToArray());
54 |
55 | if (platformComboBox.Items.Count > 0)
56 | {
57 | platformComboBox.SelectedIndex = 0;
58 | }
59 | }
60 |
61 | private void updateEnabledState()
62 | {
63 | okButton.Enabled = (emulatorComboBox.Items.Count > 0 &&
64 | emulatorComboBox.SelectedIndex != -1 &&
65 | platformComboBox.Items.Count > 0 &&
66 | platformComboBox.SelectedIndex != -1);
67 |
68 | emulatorComboBox.Enabled = (emulatorComboBox.Items.Count != 0);
69 | platformComboBox.Enabled = (platformComboBox.Items.Count != 0);
70 | }
71 |
72 | private void emulatorComboBox_SelectionChangeCommitted(object sender, EventArgs e)
73 | {
74 | populatePlatforms(emulatorComboBox.SelectedItem.ToString());
75 |
76 | updateEnabledState();
77 | }
78 |
79 | private void platformComboBox_SelectionChangeCommitted(object sender, EventArgs e)
80 | {
81 | updateEnabledState();
82 | }
83 |
84 | private void okButton_Click(object sender, EventArgs e)
85 | {
86 | Emulator = emulatorComboBox.SelectedItem.ToString();
87 | Platform = platformComboBox.SelectedItem.ToString();
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/Plugin/ArchiveListWindow.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 |
11 | namespace ArchiveCacheManager
12 | {
13 | public partial class ArchiveListWindow : Form
14 | {
15 | public string SelectedFile;
16 | public int EmulatorIndex;
17 |
18 | public ArchiveListWindow(string archiveName, string[] fileList, string[] emulatorList, string selection = "")
19 | {
20 | InitializeComponent();
21 |
22 | archiveNameLabel.Text = archiveName;
23 |
24 | emulatorComboBox.Items.Clear();
25 | if (emulatorList.Count() > 0)
26 | {
27 | emulatorComboBox.Items.AddRange(emulatorList);
28 | emulatorComboBox.SelectedIndex = 0;
29 | EmulatorIndex = emulatorComboBox.SelectedIndex;
30 | emulatorComboBox.Enabled = true;
31 | }
32 | else
33 | {
34 | emulatorComboBox.Enabled = false;
35 | }
36 |
37 | fileListGridView.Rows.Clear();
38 | for (int i = 0; i < fileList.Length; i++)
39 | {
40 | fileListGridView.Rows.Add(new object[] { fileList[i] });
41 | if (string.Equals(fileList[i], selection, StringComparison.InvariantCultureIgnoreCase))
42 | {
43 | fileListGridView.Rows[i].Selected = true;
44 | fileListGridView.CurrentCell = fileListGridView.Rows[i].Cells["File"];
45 | }
46 | }
47 |
48 | // Check that setting the selected item above actually worked. If not, set it to the first item.
49 | if (fileListGridView.SelectedRows.Count == 0)
50 | {
51 | fileListGridView.Rows[0].Selected = true;
52 | fileListGridView.CurrentCell = fileListGridView.Rows[0].Cells["File"];
53 | }
54 | SelectedFile = string.Empty;
55 |
56 | UserInterface.ApplyTheme(this);
57 | //fileListGridView.Columns["File"].DefaultCellStyle.Padding = new Padding(34, 0, 0, 0);
58 | //fileListGridView.CellPainting += fileListGridView_CellPainting;
59 | }
60 |
61 | private void okButton_Click(object sender, EventArgs e)
62 | {
63 | SelectedFile = fileListGridView.SelectedRows[0].Cells["File"].Value.ToString();
64 | EmulatorIndex = emulatorComboBox.SelectedIndex;
65 | }
66 |
67 | private void fileListBox_MouseDoubleClick(object sender, MouseEventArgs e)
68 | {
69 | okButton.PerformClick();
70 | }
71 |
72 | /*
73 | private void fileListGridView_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
74 | {
75 | int priorityIndex = 0;
76 | int selectedIndex = 0;
77 |
78 | if (e.RowIndex < 0)
79 | return;
80 |
81 | if (e.ColumnIndex == fileListGridView.Columns["File"].Index)
82 | {
83 | if (e.RowIndex == priorityIndex)
84 | {
85 | UserInterface.DrawCellIcon(e, Resources.star_blue);
86 | }
87 |
88 | if (e.RowIndex == selectedIndex)
89 | {
90 | UserInterface.DrawCellIcon(e, Resources.star, 15, false);
91 | }
92 | }
93 | }
94 | */
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/Core/Core.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {035823E0-C80B-49BF-9FAD-9C65EA45E3A9}
8 | Library
9 | Properties
10 | ArchiveCacheManager
11 | ArchiveCacheManager.Core
12 | v4.7.2
13 | 512
14 | true
15 |
16 |
17 |
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 | OnOutputUpdated
36 |
37 |
38 |
39 | ..\packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | copy /Y $(TargetDir)*.dll c:\LaunchBox\Plugins\ArchiveCacheManager
78 | mkdir $(SolutionDir)..\release\ArchiveCacheManager
79 | copy /Y $(TargetDir)*.dll $(SolutionDir)..\release\ArchiveCacheManager
80 |
81 |
82 |
--------------------------------------------------------------------------------
/thirdparty/7-Zip/License.txt:
--------------------------------------------------------------------------------
1 | 7-Zip
2 | ~~~~~
3 | License for use and distribution
4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 |
6 | 7-Zip Copyright (C) 1999-2021 Igor Pavlov.
7 |
8 | The licenses for files are:
9 |
10 | 1) 7z.dll:
11 | - The "GNU LGPL" as main license for most of the code
12 | - The "GNU LGPL" with "unRAR license restriction" for some code
13 | - The "BSD 3-clause License" for some code
14 | 2) All other files: the "GNU LGPL".
15 |
16 | Redistributions in binary form must reproduce related license information from this file.
17 |
18 | Note:
19 | You can use 7-Zip on any computer, including a computer in a commercial
20 | organization. You don't need to register or pay for 7-Zip.
21 |
22 |
23 | GNU LGPL information
24 | --------------------
25 |
26 | This library is free software; you can redistribute it and/or
27 | modify it under the terms of the GNU Lesser General Public
28 | License as published by the Free Software Foundation; either
29 | version 2.1 of the License, or (at your option) any later version.
30 |
31 | This library is distributed in the hope that it will be useful,
32 | but WITHOUT ANY WARRANTY; without even the implied warranty of
33 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
34 | Lesser General Public License for more details.
35 |
36 | You can receive a copy of the GNU Lesser General Public License from
37 | http://www.gnu.org/
38 |
39 |
40 |
41 |
42 | BSD 3-clause License
43 | --------------------
44 |
45 | The "BSD 3-clause License" is used for the code in 7z.dll that implements LZFSE data decompression.
46 | That code was derived from the code in the "LZFSE compression library" developed by Apple Inc,
47 | that also uses the "BSD 3-clause License":
48 |
49 | ----
50 | Copyright (c) 2015-2016, Apple Inc. All rights reserved.
51 |
52 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
53 |
54 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
55 |
56 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
57 | in the documentation and/or other materials provided with the distribution.
58 |
59 | 3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived
60 | from this software without specific prior written permission.
61 |
62 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
63 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
64 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
65 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
67 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
68 | ----
69 |
70 |
71 |
72 |
73 | unRAR license restriction
74 | -------------------------
75 |
76 | The decompression engine for RAR archives was developed using source
77 | code of unRAR program.
78 | All copyrights to original unRAR code are owned by Alexander Roshal.
79 |
80 | The license for original unRAR code has the following restriction:
81 |
82 | The unRAR sources cannot be used to re-create the RAR compression algorithm,
83 | which is proprietary. Distribution of modified unRAR sources in separate form
84 | or as a part of other software is permitted, provided that it is clearly
85 | stated in the documentation and source comments that the code may
86 | not be used to develop a RAR (WinRAR) compatible archiver.
87 |
88 |
89 | --
90 | Igor Pavlov
91 |
--------------------------------------------------------------------------------
/src/ArchiveCacheManager/ArchiveCacheManager.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {687F96D0-DFB8-4A53-BF23-AA02BD7658EC}
8 | Exe
9 | ArchiveCacheManager
10 | ArchiveCacheManager
11 | v4.7.2
12 | 512
13 | true
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 | icon.ico
37 |
38 |
39 | OnOutputUpdated
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | {035823e0-c80b-49bf-9fad-9c65ea45e3a9}
61 | Core
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | mkdir c:\LaunchBox\Plugins\ArchiveCacheManager
70 | copy /Y $(TargetPath) c:\LaunchBox\Plugins\ArchiveCacheManager
71 | mkdir $(SolutionDir)..\release\ArchiveCacheManager
72 | copy /Y $(TargetPath) $(SolutionDir)..\release\ArchiveCacheManager
73 | copy /Y $(SolutionDir)..\README.md $(SolutionDir)..\release\ArchiveCacheManager\readme.txt
74 | copy /Y $(SolutionDir)..\HISTORY.md $(SolutionDir)..\release\ArchiveCacheManager\history.txt
75 | mkdir $(SolutionDir)..\release\ArchiveCacheManager\7-Zip
76 | copy /Y $(SolutionDir)..\thirdparty\7-Zip\* $(SolutionDir)..\release\ArchiveCacheManager\7-Zip
77 | move /Y $(SolutionDir)..\release\ArchiveCacheManager\7-Zip\7z.exe $(SolutionDir)..\release\ArchiveCacheManager\7-Zip\7z.exe.original
78 | move /Y $(SolutionDir)..\release\ArchiveCacheManager\7-Zip\7z.dll $(SolutionDir)..\release\ArchiveCacheManager\7-Zip\7z.dll.original
79 | mkdir $(SolutionDir)..\release\ArchiveCacheManager\Badges
80 | copy /Y $(SolutionDir)Plugin\Resources\Badges $(SolutionDir)..\release\ArchiveCacheManager\Badges
81 | del $(SolutionDir)..\release\*.zip
82 | $(SolutionDir)..\thirdparty\7-Zip\7z.exe a $(SolutionDir)..\release\ArchiveCacheManager.zip $(SolutionDir)..\release\*
83 |
84 |
--------------------------------------------------------------------------------
/src/Plugin/ArchiveListWindowBigBox.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 | using Unbroken.LaunchBox.Plugins;
11 | using Unbroken.LaunchBox.Plugins.Data;
12 |
13 | namespace ArchiveCacheManager
14 | {
15 | public partial class ArchiveListWindowBigBox : Form //, IBigBoxThemeElementPlugin
16 | {
17 | public string SelectedFile;
18 |
19 | public ArchiveListWindowBigBox(string archiveName, string[] fileList, string selection = "")
20 | {
21 | InitializeComponent();
22 |
23 | UserInterface.ScaleControlFont(fileListBox, 96.0f / fileListBox.DeviceDpi);
24 | UserInterface.ScaleControlFont(archiveNameLabel, 96.0f / archiveNameLabel.DeviceDpi);
25 |
26 | if (LaunchBoxSettings.HideMouseCursor)
27 | {
28 | Cursor.Hide();
29 | }
30 |
31 | archiveNameLabel.Text = archiveName;
32 |
33 | fileListBox.Items.Clear();
34 | fileListBox.Items.AddRange(fileList);
35 | if (selection != string.Empty)
36 | {
37 | fileListBox.SelectedItem = selection;
38 | }
39 | // Check that setting the selected item above actually worked. If not, set it to the first item.
40 | if (fileListBox.SelectedItems.Count == 0)
41 | {
42 | fileListBox.SelectedIndex = 0;
43 | }
44 | SelectedFile = string.Empty;
45 | }
46 |
47 | private void FileListBox_DrawItem(object sender, DrawItemEventArgs e)
48 | {
49 | e.DrawBackground();
50 | Graphics g = e.Graphics;
51 | Brush brush = ((e.State & DrawItemState.Selected) == DrawItemState.Selected) ?
52 | new SolidBrush(Color.FromArgb(0x5F, 0x33, 0x99, 0xFF)) : new SolidBrush(e.BackColor);
53 | g.FillRectangle(brush, e.Bounds);
54 | e.Graphics.DrawString(" " + fileListBox.Items[e.Index].ToString(), e.Font,
55 | new SolidBrush(e.ForeColor), e.Bounds, StringFormat.GenericDefault);
56 | //e.DrawFocusRectangle();
57 | }
58 |
59 | private void okButton_Click(object sender, EventArgs e)
60 | {
61 | SelectedFile = fileListBox.SelectedItem.ToString();
62 | }
63 |
64 | private void fileListBox_MouseDoubleClick(object sender, MouseEventArgs e)
65 | {
66 | okButton.PerformClick();
67 | }
68 |
69 |
70 |
71 |
72 | #if false
73 | public void OnSelectionChanged(FilterType filterType, string filterValue, IPlatform platform, IPlatformCategory category, IPlaylist playlist, IGame game)
74 | {
75 |
76 | }
77 |
78 | public bool OnEnter()
79 | {
80 | SelectedFile = fileListBox.SelectedItem.ToString();
81 |
82 | this.DialogResult = DialogResult.OK;
83 | this.Close();
84 |
85 | return true;
86 | }
87 |
88 | public bool OnEscape()
89 | {
90 | this.DialogResult = DialogResult.Cancel;
91 | this.Close();
92 |
93 | return true;
94 | }
95 |
96 | public bool OnUp(bool held)
97 | {
98 | if (fileListBox.SelectedIndex > 0)
99 | {
100 | fileListBox.SelectedIndex--;
101 | }
102 |
103 | return true;
104 | }
105 |
106 | public bool OnDown(bool held)
107 | {
108 | if (fileListBox.SelectedIndex < fileListBox.Items.Count - 1)
109 | {
110 | fileListBox.SelectedIndex++;
111 | }
112 |
113 | return true;
114 | }
115 |
116 | public bool OnLeft(bool held)
117 | {
118 | return true;
119 | }
120 |
121 | public bool OnRight(bool held)
122 | {
123 | return true;
124 | }
125 |
126 | public bool OnPageDown()
127 | {
128 | return true;
129 | }
130 |
131 | public bool OnPageUp()
132 | {
133 | return true;
134 | }
135 | #endif
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/src/Plugin/MessageBoxBigBox.Designer.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace ArchiveCacheManager
3 | {
4 | partial class MessageBoxBigBox
5 | {
6 | ///
7 | /// Required designer variable.
8 | ///
9 | private System.ComponentModel.IContainer components = null;
10 |
11 | ///
12 | /// Clean up any resources being used.
13 | ///
14 | /// true if managed resources should be disposed; otherwise, false.
15 | protected override void Dispose(bool disposing)
16 | {
17 | if (disposing && (components != null))
18 | {
19 | components.Dispose();
20 | }
21 | base.Dispose(disposing);
22 | }
23 |
24 | #region Windows Form Designer generated code
25 |
26 | ///
27 | /// Required method for Designer support - do not modify
28 | /// the contents of this method with the code editor.
29 | ///
30 | private void InitializeComponent()
31 | {
32 | this.message = new System.Windows.Forms.Label();
33 | this.cancelButton = new System.Windows.Forms.Button();
34 | this.okButton = new System.Windows.Forms.Button();
35 | this.SuspendLayout();
36 | //
37 | // message
38 | //
39 | this.message.BackColor = System.Drawing.Color.Black;
40 | this.message.Font = new System.Drawing.Font("Calibri", 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
41 | this.message.ForeColor = System.Drawing.Color.White;
42 | this.message.Location = new System.Drawing.Point(3, 3);
43 | this.message.Margin = new System.Windows.Forms.Padding(0);
44 | this.message.Name = "message";
45 | this.message.Size = new System.Drawing.Size(794, 294);
46 | this.message.TabIndex = 5;
47 | this.message.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
48 | //
49 | // cancelButton
50 | //
51 | this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
52 | this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
53 | this.cancelButton.Image = global::ArchiveCacheManager.Resources.cross_script;
54 | this.cancelButton.Location = new System.Drawing.Point(403, 89);
55 | this.cancelButton.Name = "cancelButton";
56 | this.cancelButton.Size = new System.Drawing.Size(75, 23);
57 | this.cancelButton.TabIndex = 8;
58 | this.cancelButton.Text = "Cancel";
59 | this.cancelButton.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
60 | this.cancelButton.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
61 | this.cancelButton.UseVisualStyleBackColor = true;
62 | //
63 | // okButton
64 | //
65 | this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
66 | this.okButton.DialogResult = System.Windows.Forms.DialogResult.OK;
67 | this.okButton.Image = global::ArchiveCacheManager.Resources.tick;
68 | this.okButton.Location = new System.Drawing.Point(322, 89);
69 | this.okButton.Name = "okButton";
70 | this.okButton.Size = new System.Drawing.Size(75, 23);
71 | this.okButton.TabIndex = 7;
72 | this.okButton.Text = "Play!";
73 | this.okButton.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
74 | this.okButton.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
75 | this.okButton.UseVisualStyleBackColor = true;
76 | //
77 | // MessageBoxBigBox
78 | //
79 | this.AcceptButton = this.okButton;
80 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
81 | this.BackColor = System.Drawing.Color.DarkGray;
82 | this.CancelButton = this.cancelButton;
83 | this.ClientSize = new System.Drawing.Size(800, 300);
84 | this.Controls.Add(this.message);
85 | this.Controls.Add(this.cancelButton);
86 | this.Controls.Add(this.okButton);
87 | this.DoubleBuffered = true;
88 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
89 | this.Name = "MessageBoxBigBox";
90 | this.Opacity = 0.95D;
91 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
92 | this.Text = "Message Box";
93 | this.ResumeLayout(false);
94 |
95 | }
96 |
97 | #endregion
98 |
99 | private System.Windows.Forms.Label message;
100 | private System.Windows.Forms.Button cancelButton;
101 | private System.Windows.Forms.Button okButton;
102 | }
103 | }
--------------------------------------------------------------------------------
/src/Plugin/GameMenuItem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.IO;
8 | using Unbroken.LaunchBox.Plugins;
9 | using Unbroken.LaunchBox.Plugins.Data;
10 | using System.Windows.Forms;
11 | using System.Windows.Interop;
12 |
13 | namespace ArchiveCacheManager
14 | {
15 | class GameMenuItem : IGameMenuItemPlugin
16 | {
17 | public bool SupportsMultipleGames => false;
18 | public string Caption => PluginHelper.StateManager.IsBigBox ? "Select ROM In Archive" : "Select ROM In Archive...";
19 | public Image IconImage => Resources.icon16x16_play;
20 | public bool ShowInLaunchBox => true;
21 | public bool ShowInBigBox => true;
22 |
23 | public bool GetIsValidForGame(IGame selectedGame) => Zip.SupportedType(selectedGame.ApplicationPath)
24 | && PluginUtils.GetEmulatorPlatformAutoExtract(selectedGame.EmulatorId, selectedGame.Platform);
25 | public bool GetIsValidForGames(IGame[] selectedGames) => false;
26 |
27 | public void OnSelected(IGame selectedGame)
28 | {
29 | string path = PathUtils.GetAbsolutePath(selectedGame.ApplicationPath);
30 |
31 | if (File.Exists(path))
32 | {
33 | // HACK
34 | // In case where game is launched, but launch failed or aborted, 7z isn't cleaned up. If this code then runs, it will
35 | // call the archive cache manager version of 7z, which will not return the correct results (file priority will be applied,
36 | // and the first file listing removed. Restore 7z here, just in case it wasn't cleaned up properly previously.
37 | GameLaunching.Restore7z();
38 |
39 | string[] fileList = new Zip().List(path);
40 |
41 | if (fileList.Count() == 0)
42 | {
43 | string errorMessage = string.Format("Error listing contents of {0}.\r\n\r\nCheck {1} for details.", Path.GetFileName(selectedGame.ApplicationPath), Path.GetFileName(PathUtils.GetLogFilePath()));
44 |
45 | if (PluginHelper.StateManager.IsBigBox)
46 | {
47 | MessageBoxBigBox messageBox = new MessageBoxBigBox(errorMessage);
48 | messageBox.ShowDialog();
49 | }
50 | else
51 | {
52 | UserInterface.ErrorDialog(errorMessage);
53 | }
54 |
55 | return;
56 | }
57 |
58 | var emulatorsTuple = PluginUtils.GetPlatformEmulators(selectedGame.Platform, selectedGame.EmulatorId);
59 |
60 | Form window;
61 | if (PluginHelper.StateManager.IsBigBox)
62 | {
63 | window = new ArchiveListWindowBigBox(Path.GetFileName(selectedGame.ApplicationPath), fileList, GameIndex.GetSelectedFile(selectedGame.Id));
64 | }
65 | else
66 | {
67 | window = new ArchiveListWindow(Path.GetFileName(selectedGame.ApplicationPath), fileList, emulatorsTuple.Select(emu => PluginUtils.GetEmulatorTitle(emu.Item1, emu.Item2)).ToArray(), GameIndex.GetSelectedFile(selectedGame.Id));
68 | }
69 | //NativeWindow parent = new NativeWindow();
70 |
71 | // Glue between the main app window (WPF) and this window (WinForms)
72 | //parent.AssignHandle(new WindowInteropHelper(System.Windows.Application.Current.MainWindow).Handle);
73 | window.ShowDialog();// parent);
74 |
75 | if (window.DialogResult == DialogResult.OK)
76 | {
77 | if (PluginHelper.StateManager.IsBigBox)
78 | {
79 | GameIndex.SetSelectedFile(selectedGame.Id, (window as ArchiveListWindowBigBox).SelectedFile);
80 | PluginHelper.BigBoxMainViewModel.PlayGame(selectedGame, null, PluginHelper.DataManager.GetEmulatorById(selectedGame.EmulatorId), null);
81 | }
82 | else
83 | {
84 | int emulatorIndex = (window as ArchiveListWindow).EmulatorIndex;
85 | // Use a specific command line for the IEmulatorPlatform. This covers the case where RetroArch has more than one core configured for the same platform.
86 | string commandLine = emulatorsTuple[emulatorIndex].Item2.CommandLine;
87 | // Use the game's custom command line if it exists and we're running with the game's emulator (index 0)
88 | if (emulatorIndex == 0 && !string.IsNullOrEmpty(selectedGame.CommandLine))
89 | {
90 | commandLine = selectedGame.CommandLine;
91 | }
92 | GameIndex.SetSelectedFile(selectedGame.Id, (window as ArchiveListWindow).SelectedFile);
93 | PluginHelper.LaunchBoxMainViewModel.PlayGame(selectedGame, null, emulatorsTuple[emulatorIndex].Item1, commandLine);
94 | }
95 | }
96 | }
97 | else
98 | {
99 | UserInterface.ErrorDialog($"Couldn't find the archive file:\r\n\r\n{path}");
100 | }
101 | }
102 |
103 | public void OnSelected(IGame[] selectedGames)
104 | {
105 |
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/Core/Extractors/Chdman.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.IO;
7 | using System.Text.RegularExpressions;
8 |
9 | namespace ArchiveCacheManager
10 | {
11 | public class Chdman : Extractor
12 | {
13 | string executablePath = Path.Combine(PathUtils.GetExtractorRootPath(), "chdman.exe");
14 |
15 | public Chdman()
16 | {
17 |
18 | }
19 |
20 | public static bool SupportedType(string archivePath)
21 | {
22 | return PathUtils.HasExtension(archivePath, new string[] { ".chd" });
23 | }
24 |
25 | public override bool Extract(string archivePath, string cachePath, string[] includeList = null, string[] excludeList = null)
26 | {
27 | string args = string.Format("extractcd -i \"{0}\" -o \"{1}\" -f", archivePath, Path.Combine(cachePath, Path.GetFileNameWithoutExtension(archivePath) + ".cue"));
28 |
29 | // chdman reports the progress status on stderr, not stdout
30 | (string stdout, string stderr, int exitCode) = ProcessUtils.RunProcess(executablePath, args, false, null, true, ExtractionProgress);
31 |
32 | if (exitCode != 0)
33 | {
34 | Logger.Log(string.Format("chdman returned exit code {0} with error output:\r\n{1}", exitCode, stderr));
35 | Environment.ExitCode = exitCode;
36 | }
37 |
38 | return exitCode == 0;
39 | }
40 |
41 | public override long GetSize(string archivePath, string fileInArchive = null)
42 | {
43 | string args = string.Format("info -i \"{0}\"", archivePath);
44 |
45 | (string stdout, string stderr, int exitCode) = ProcessUtils.RunProcess(executablePath, args);
46 |
47 | if (exitCode != 0)
48 | {
49 | Logger.Log(string.Format("chdman returned exit code {0} with error output:\r\n{1}", exitCode, stderr));
50 | Environment.ExitCode = exitCode;
51 | }
52 |
53 | /*
54 | stdout will be in the format below:
55 | ------
56 | c:\LaunchBox\ThirdParty\chdman>chdman info -i "c:\Emulation\ROMs\Doom (USA).zip"
57 | chdman - MAME Compressed Hunks of Data (CHD) manager 0.242 (mame0242)
58 | Input file: c:\Emulation\ROMs\Sony - Playstation\Doom (USA).chd
59 | File Version: 5
60 | Logical size: 302,660,928 bytes
61 | Hunk Size: 19,584 bytes
62 | Total Hunks: 15,455
63 | Unit Size: 2,448 bytes
64 | Total Units: 123,636
65 | Compression: cdlz (CD LZMA), cdzl (CD Deflate), cdfl (CD FLAC)
66 | CHD size: 182,307,697 bytes
67 | Ratio: 60.2%
68 | SHA1: 1fe56d1e220712bdc2681bb55f2e90b457cc593b
69 | Data SHA1: cdcd62e6d75a6e22a9f5172c5c9175def92dce84
70 | Metadata: Tag='CHT2' Index=0 Length=92 bytes
71 | TRACK:1 TYPE:MODE2_RAW SUBTYPE:NONE FRAMES:35789 PREGAP:0 PG
72 | Metadata: Tag='CHT2' Index=1 Length=91 bytes
73 | TRACK:2 TYPE:AUDIO SUBTYPE:NONE FRAMES:14344 PREGAP:150 PGTY
74 | Metadata: Tag='CHT2' Index=2 Length=90 bytes
75 | TRACK:3 TYPE:AUDIO SUBTYPE:NONE FRAMES:8844 PREGAP:150 PGTYP
76 | Metadata: Tag='CHT2' Index=3 Length=91 bytes
77 | TRACK:4 TYPE:AUDIO SUBTYPE:NONE FRAMES:17854 PREGAP:150 PGTY
78 | Metadata: Tag='CHT2' Index=4 Length=91 bytes
79 | TRACK:5 TYPE:AUDIO SUBTYPE:NONE FRAMES:15611 PREGAP:150 PGTY
80 | Metadata: Tag='CHT2' Index=5 Length=90 bytes
81 | TRACK:6 TYPE:AUDIO SUBTYPE:NONE FRAMES:9752 PREGAP:150 PGTYP
82 | Metadata: Tag='CHT2' Index=6 Length=90 bytes
83 | TRACK:7 TYPE:AUDIO SUBTYPE:NONE FRAMES:4187 PREGAP:150 PGTYP
84 | Metadata: Tag='CHT2' Index=7 Length=91 bytes
85 | TRACK:8 TYPE:AUDIO SUBTYPE:NONE FRAMES:17245 PREGAP:150 PGTY
86 | */
87 |
88 | long size = 0;
89 |
90 | if (exitCode == 0)
91 | {
92 | string[] stdoutArray = stdout.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
93 | // We use the "logical size" as the uncompressed size, and while this isn't accurate, it's good enough.
94 | // Find the string beginning with "Logical size:", then take the substring after it which will be "xxx,xxx,xxx bytes"
95 | string sizeString = Array.Find(stdoutArray, a => a.StartsWith("Logical size:")).Substring(14);
96 | // Remove the trailing " bytes" from the string, leaving "xxx,xxx,xxx"
97 | sizeString = sizeString.Split(" ".ToSingleArray(), StringSplitOptions.RemoveEmptyEntries)[0];
98 | sizeString = sizeString.Replace(",", string.Empty);
99 | size = Convert.ToInt64(sizeString);
100 | }
101 |
102 | return size;
103 | }
104 |
105 | public override string[] List(string archivePath)
106 | {
107 | string[] fileList = new string[2];
108 | fileList[0] = Path.GetFileNameWithoutExtension(archivePath) + ".cue";
109 | fileList[1] = Path.GetFileNameWithoutExtension(archivePath) + ".bin";
110 | return fileList;
111 | }
112 |
113 | public override string Name()
114 | {
115 | return "chdman";
116 | }
117 |
118 | public override string GetExtractorPath()
119 | {
120 | return executablePath;
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/src/Plugin/MessageBoxBigBox.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/src/ArchiveCacheManager/Program.cs:
--------------------------------------------------------------------------------
1 | /* Archive Cache Manager - A LaunchBox plugin which extracts and caches ROM
2 | * archives, letting you play games faster.
3 | *
4 | * Copyright (C) 2021 fraganator
5 | *
6 | * This library is free software; you can redistribute it and/or
7 | * modify it under the terms of the GNU Lesser General Public
8 | * License as published by the Free Software Foundation; either
9 | * version 2.1 of the License, or (at your option) any later version.
10 | *
11 | * This library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | * Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public
17 | * License along with this library; if not, write to the Free Software
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 | * USA
20 | *
21 | * Links:
22 | * Plugin Homepage - https://forums.launchbox-app.com/files/file/234-archive-cache-manager/
23 | * Forum Support - https://forums.launchbox-app.com/topic/35010-archive-cache-manager/
24 | * GitHub Repository - https://github.com/fraganator/archive-cache-manager
25 | *
26 | * Contact:
27 | * GitHub - https://github.com/fraganator
28 | * LaunchBox Forum - https://forums.launchbox-app.com/profile/69812-fraganator/
29 | */
30 |
31 | /* NOTES ON LAUNCHBOX AND 7-ZIP
32 | *
33 | * When an emulator has the "Extract ROM archives before running option"
34 | * checked and a game is launched, 7z is called twice. The first call extracts
35 | * the archive with the command:
36 | *
37 | * 7z.exe x -o