├── .gitignore
├── LICENSE
├── README.md
├── mfs_gui
├── App.config
├── FolderSelectDialog
│ ├── FolderSelectDialog.cs
│ └── Reflector.cs
├── Icons
│ ├── BlueDisk.ico
│ ├── BlueDisk.png
│ ├── Filetypes
│ │ ├── CARD.png
│ │ ├── CRSD.png
│ │ ├── File.png
│ │ ├── GSBLK.png
│ │ ├── GSEXP.png
│ │ ├── MA2D1.png
│ │ ├── MA3D1.png
│ │ ├── OPT.png
│ │ ├── PSDNS.png
│ │ ├── PSMAS.png
│ │ ├── PSPPM.png
│ │ ├── PSSEA.png
│ │ ├── TSANL.png
│ │ ├── TSANM.png
│ │ ├── TSBGA.png
│ │ ├── TSBGL.png
│ │ ├── TSTLL.png
│ │ └── TSTLT.png
│ ├── GreyDisk16.png
│ └── Storage
│ │ ├── 00.png
│ │ ├── 01.png
│ │ ├── 02.png
│ │ ├── 03.png
│ │ ├── 04.png
│ │ ├── 05.png
│ │ ├── 06.png
│ │ ├── 07.png
│ │ ├── 08.png
│ │ ├── 09.png
│ │ └── 10.png
├── MainForm.Designer.cs
├── MainForm.cs
├── MainForm.resx
├── Program.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── changelog.txt
├── license.txt
├── mfs_gui.csproj
└── readme.txt
├── mfs_library
├── Leo
│ ├── Leo.cs
│ └── LeoDisk.cs
├── MA
│ ├── MA2D1.cs
│ └── Yay1.cs
├── MFS
│ ├── MFS.cs
│ ├── MFSDef.cs
│ ├── MFSDisk.cs
│ ├── MFSUtil_Directory.cs
│ ├── MFSUtil_File.cs
│ └── MFSUtil_Other.cs
├── Properties
│ └── AssemblyInfo.cs
├── Util
│ ├── SJISUtil.cs
│ └── Util.cs
└── mfs_library.csproj
├── mfs_manager.sln
├── mfs_manager
├── App.config
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
└── mfs_manager.csproj
└── save_manager
├── App.config
├── MainForm.Designer.cs
├── MainForm.cs
├── MainForm.resx
├── Program.cs
├── Properties
├── AssemblyInfo.cs
├── Resources.Designer.cs
├── Resources.resx
├── Settings.Designer.cs
└── Settings.settings
└── save_manager.csproj
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # Visual Studio 2017 auto generated files
33 | Generated\ Files/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # Benchmark Results
49 | BenchmarkDotNet.Artifacts/
50 |
51 | # .NET Core
52 | project.lock.json
53 | project.fragment.lock.json
54 | artifacts/
55 | **/Properties/launchSettings.json
56 |
57 | # StyleCop
58 | StyleCopReport.xml
59 |
60 | # Files built by Visual Studio
61 | *_i.c
62 | *_p.c
63 | *_i.h
64 | *.ilk
65 | *.meta
66 | *.obj
67 | *.iobj
68 | *.pch
69 | *.pdb
70 | *.ipdb
71 | *.pgc
72 | *.pgd
73 | *.rsp
74 | *.sbr
75 | *.tlb
76 | *.tli
77 | *.tlh
78 | *.tmp
79 | *.tmp_proj
80 | *.log
81 | *.vspscc
82 | *.vssscc
83 | .builds
84 | *.pidb
85 | *.svclog
86 | *.scc
87 |
88 | # Chutzpah Test files
89 | _Chutzpah*
90 |
91 | # Visual C++ cache files
92 | ipch/
93 | *.aps
94 | *.ncb
95 | *.opendb
96 | *.opensdf
97 | *.sdf
98 | *.cachefile
99 | *.VC.db
100 | *.VC.VC.opendb
101 |
102 | # Visual Studio profiler
103 | *.psess
104 | *.vsp
105 | *.vspx
106 | *.sap
107 |
108 | # Visual Studio Trace Files
109 | *.e2e
110 |
111 | # TFS 2012 Local Workspace
112 | $tf/
113 |
114 | # Guidance Automation Toolkit
115 | *.gpState
116 |
117 | # ReSharper is a .NET coding add-in
118 | _ReSharper*/
119 | *.[Rr]e[Ss]harper
120 | *.DotSettings.user
121 |
122 | # JustCode is a .NET coding add-in
123 | .JustCode
124 |
125 | # TeamCity is a build add-in
126 | _TeamCity*
127 |
128 | # DotCover is a Code Coverage Tool
129 | *.dotCover
130 |
131 | # AxoCover is a Code Coverage Tool
132 | .axoCover/*
133 | !.axoCover/settings.json
134 |
135 | # Visual Studio code coverage results
136 | *.coverage
137 | *.coveragexml
138 |
139 | # NCrunch
140 | _NCrunch_*
141 | .*crunch*.local.xml
142 | nCrunchTemp_*
143 |
144 | # MightyMoose
145 | *.mm.*
146 | AutoTest.Net/
147 |
148 | # Web workbench (sass)
149 | .sass-cache/
150 |
151 | # Installshield output folder
152 | [Ee]xpress/
153 |
154 | # DocProject is a documentation generator add-in
155 | DocProject/buildhelp/
156 | DocProject/Help/*.HxT
157 | DocProject/Help/*.HxC
158 | DocProject/Help/*.hhc
159 | DocProject/Help/*.hhk
160 | DocProject/Help/*.hhp
161 | DocProject/Help/Html2
162 | DocProject/Help/html
163 |
164 | # Click-Once directory
165 | publish/
166 |
167 | # Publish Web Output
168 | *.[Pp]ublish.xml
169 | *.azurePubxml
170 | # Note: Comment the next line if you want to checkin your web deploy settings,
171 | # but database connection strings (with potential passwords) will be unencrypted
172 | *.pubxml
173 | *.publishproj
174 |
175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
176 | # checkin your Azure Web App publish settings, but sensitive information contained
177 | # in these scripts will be unencrypted
178 | PublishScripts/
179 |
180 | # NuGet Packages
181 | *.nupkg
182 | # The packages folder can be ignored because of Package Restore
183 | **/[Pp]ackages/*
184 | # except build/, which is used as an MSBuild target.
185 | !**/[Pp]ackages/build/
186 | # Uncomment if necessary however generally it will be regenerated when needed
187 | #!**/[Pp]ackages/repositories.config
188 | # NuGet v3's project.json files produces more ignorable files
189 | *.nuget.props
190 | *.nuget.targets
191 |
192 | # Microsoft Azure Build Output
193 | csx/
194 | *.build.csdef
195 |
196 | # Microsoft Azure Emulator
197 | ecf/
198 | rcf/
199 |
200 | # Windows Store app package directories and files
201 | AppPackages/
202 | BundleArtifacts/
203 | Package.StoreAssociation.xml
204 | _pkginfo.txt
205 | *.appx
206 |
207 | # Visual Studio cache files
208 | # files ending in .cache can be ignored
209 | *.[Cc]ache
210 | # but keep track of directories ending in .cache
211 | !*.[Cc]ache/
212 |
213 | # Others
214 | ClientBin/
215 | ~$*
216 | *~
217 | *.dbmdl
218 | *.dbproj.schemaview
219 | *.jfm
220 | *.pfx
221 | *.publishsettings
222 | orleans.codegen.cs
223 |
224 | # Including strong name files can present a security risk
225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
226 | #*.snk
227 |
228 | # Since there are multiple workflows, uncomment next line to ignore bower_components
229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
230 | #bower_components/
231 |
232 | # RIA/Silverlight projects
233 | Generated_Code/
234 |
235 | # Backup & report files from converting an old project file
236 | # to a newer Visual Studio version. Backup files are not needed,
237 | # because we have git ;-)
238 | _UpgradeReport_Files/
239 | Backup*/
240 | UpgradeLog*.XML
241 | UpgradeLog*.htm
242 | ServiceFabricBackup/
243 | *.rptproj.bak
244 |
245 | # SQL Server files
246 | *.mdf
247 | *.ldf
248 | *.ndf
249 |
250 | # Business Intelligence projects
251 | *.rdl.data
252 | *.bim.layout
253 | *.bim_*.settings
254 | *.rptproj.rsuser
255 |
256 | # Microsoft Fakes
257 | FakesAssemblies/
258 |
259 | # GhostDoc plugin setting file
260 | *.GhostDoc.xml
261 |
262 | # Node.js Tools for Visual Studio
263 | .ntvs_analysis.dat
264 | node_modules/
265 |
266 | # Visual Studio 6 build log
267 | *.plg
268 |
269 | # Visual Studio 6 workspace options file
270 | *.opt
271 |
272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
273 | *.vbw
274 |
275 | # Visual Studio LightSwitch build output
276 | **/*.HTMLClient/GeneratedArtifacts
277 | **/*.DesktopClient/GeneratedArtifacts
278 | **/*.DesktopClient/ModelManifest.xml
279 | **/*.Server/GeneratedArtifacts
280 | **/*.Server/ModelManifest.xml
281 | _Pvt_Extensions
282 |
283 | # Paket dependency manager
284 | .paket/paket.exe
285 | paket-files/
286 |
287 | # FAKE - F# Make
288 | .fake/
289 |
290 | # JetBrains Rider
291 | .idea/
292 | *.sln.iml
293 |
294 | # CodeRush
295 | .cr/
296 |
297 | # Python Tools for Visual Studio (PTVS)
298 | __pycache__/
299 | *.pyc
300 |
301 | # Cake - Uncomment if you are using it
302 | # tools/**
303 | # !tools/packages.config
304 |
305 | # Tabs Studio
306 | *.tss
307 |
308 | # Telerik's JustMock configuration file
309 | *.jmconfig
310 |
311 | # BizTalk build output
312 | *.btp.cs
313 | *.btm.cs
314 | *.odx.cs
315 | *.xsd.cs
316 |
317 | # OpenCover UI analysis results
318 | OpenCover/
319 |
320 | # Azure Stream Analytics local run output
321 | ASALocalRun/
322 |
323 | # MSBuild Binary and Structured Log
324 | *.binlog
325 |
326 | # NVidia Nsight GPU debugger configuration file
327 | *.nvuser
328 |
329 | # MFractors (Xamarin productivity tool) working folder
330 | .mfractor/
331 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 LuigiBlood
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 64DD MFS Manager
2 |
3 | Contains three projects:
4 | - **mfs_library**: the main library for disk and MFS access
5 | - **mfs_manager**: the command line utility project
6 | - **mfs_gui**: the user friendly utility
7 | - **save_manager**: basic RAW import/export of disk RAM area
8 |
9 | This software can be used to manage files in 64DD titles that uses MFS for save data.
10 | You can import, extract, copy, move and rename files.
11 |
12 | Supports *.ndd disk images (64DD Dump Tool), *.disk (MAME 64DD disk image format), and *.ram (Pure 64DD disk RAM Partition image).
13 |
14 | The only known titles to use MFS are:
15 | - Mario Artist Paint Studio
16 | - Mario Artist Talent Studio
17 | - Mario Artist Communication Kit
18 | - Mario Artist Polygon Studio
19 | - Japan Pro Golf Tour 64 (do not delete zero3MByte.dat)
20 | - F-Zero X Expansion Kit
21 | - Randnet Disk
22 |
23 | Watch out to make sure to use the proper directories for save management.
24 |
--------------------------------------------------------------------------------
/mfs_gui/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/mfs_gui/FolderSelectDialog/FolderSelectDialog.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 |
4 | // ------------------------------------------------------------------
5 | // Wraps System.Windows.Forms.OpenFileDialog to make it present
6 | // a vista-style dialog.
7 | // ------------------------------------------------------------------
8 |
9 | namespace FolderSelect
10 | {
11 | ///
12 | /// Wraps System.Windows.Forms.OpenFileDialog to make it present
13 | /// a vista-style dialog.
14 | ///
15 | public class FolderSelectDialog
16 | {
17 | // Wrapped dialog
18 | System.Windows.Forms.OpenFileDialog ofd = null;
19 |
20 | ///
21 | /// Default constructor
22 | ///
23 | public FolderSelectDialog()
24 | {
25 | ofd = new System.Windows.Forms.OpenFileDialog();
26 |
27 | ofd.Filter = "Folders|\n";
28 | ofd.AddExtension = false;
29 | ofd.CheckFileExists = false;
30 | ofd.DereferenceLinks = true;
31 | ofd.Multiselect = false;
32 | }
33 |
34 | #region Properties
35 |
36 | ///
37 | /// Gets/Sets the initial folder to be selected. A null value selects the current directory.
38 | ///
39 | public string InitialDirectory
40 | {
41 | get { return ofd.InitialDirectory; }
42 | set { ofd.InitialDirectory = value == null || value.Length == 0 ? Environment.CurrentDirectory : value; }
43 | }
44 |
45 | ///
46 | /// Gets/Sets the title to show in the dialog
47 | ///
48 | public string Title
49 | {
50 | get { return ofd.Title; }
51 | set { ofd.Title = value == null ? "Select a folder" : value; }
52 | }
53 |
54 | ///
55 | /// Gets the selected folder
56 | ///
57 | public string FileName
58 | {
59 | get { return ofd.FileName; }
60 | }
61 |
62 | #endregion
63 |
64 | #region Methods
65 |
66 | ///
67 | /// Shows the dialog
68 | ///
69 | /// True if the user presses OK else false
70 | public bool ShowDialog()
71 | {
72 | return ShowDialog(IntPtr.Zero);
73 | }
74 |
75 | ///
76 | /// Shows the dialog
77 | ///
78 | /// Handle of the control to be parent
79 | /// True if the user presses OK else false
80 | public bool ShowDialog(IntPtr hWndOwner)
81 | {
82 | bool flag = false;
83 |
84 | if (Environment.OSVersion.Version.Major >= 6)
85 | {
86 | var r = new Reflector("System.Windows.Forms");
87 |
88 | uint num = 0;
89 | Type typeIFileDialog = r.GetType("FileDialogNative.IFileDialog");
90 | object dialog = r.Call(ofd, "CreateVistaDialog");
91 | r.Call(ofd, "OnBeforeVistaDialog", dialog);
92 |
93 | uint options = (uint)r.CallAs(typeof(System.Windows.Forms.FileDialog), ofd, "GetOptions");
94 | options |= (uint)r.GetEnum("FileDialogNative.FOS", "FOS_PICKFOLDERS");
95 | r.CallAs(typeIFileDialog, dialog, "SetOptions", options);
96 |
97 | object pfde = r.New("FileDialog.VistaDialogEvents", ofd);
98 | object[] parameters = new object[] { pfde, num };
99 | r.CallAs2(typeIFileDialog, dialog, "Advise", parameters);
100 | num = (uint)parameters[1];
101 | try
102 | {
103 | int num2 = (int)r.CallAs(typeIFileDialog, dialog, "Show", hWndOwner);
104 | flag = 0 == num2;
105 | }
106 | finally
107 | {
108 | r.CallAs(typeIFileDialog, dialog, "Unadvise", num);
109 | GC.KeepAlive(pfde);
110 | }
111 | }
112 | else
113 | {
114 | var fbd = new FolderBrowserDialog();
115 | fbd.Description = this.Title;
116 | fbd.SelectedPath = this.InitialDirectory;
117 | fbd.ShowNewFolderButton = false;
118 | if (fbd.ShowDialog(new WindowWrapper(hWndOwner)) != DialogResult.OK) return false;
119 | ofd.FileName = fbd.SelectedPath;
120 | flag = true;
121 | }
122 |
123 | return flag;
124 | }
125 |
126 | #endregion
127 | }
128 |
129 | ///
130 | /// Creates IWin32Window around an IntPtr
131 | ///
132 | public class WindowWrapper : System.Windows.Forms.IWin32Window
133 | {
134 | ///
135 | /// Constructor
136 | ///
137 | /// Handle to wrap
138 | public WindowWrapper(IntPtr handle)
139 | {
140 | _hwnd = handle;
141 | }
142 |
143 | ///
144 | /// Original ptr
145 | ///
146 | public IntPtr Handle
147 | {
148 | get { return _hwnd; }
149 | }
150 |
151 | private IntPtr _hwnd;
152 | }
153 |
154 | }
155 |
--------------------------------------------------------------------------------
/mfs_gui/FolderSelectDialog/Reflector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 |
4 | namespace FolderSelect
5 | {
6 | ///
7 | /// This class is from the Front-End for Dosbox and is used to present a 'vista' dialog box to select folders.
8 | /// Being able to use a vista style dialog box to select folders is much better then using the shell folder browser.
9 | /// http://code.google.com/p/fed/
10 | ///
11 | /// Example:
12 | /// var r = new Reflector("System.Windows.Forms");
13 | ///
14 | public class Reflector
15 | {
16 | #region variables
17 |
18 | string m_ns;
19 | Assembly m_asmb;
20 |
21 | #endregion
22 |
23 | #region Constructors
24 |
25 | ///
26 | /// Constructor
27 | ///
28 | /// The namespace containing types to be used
29 | public Reflector(string ns)
30 | : this(ns, ns)
31 | { }
32 |
33 | ///
34 | /// Constructor
35 | ///
36 | /// A specific assembly name (used if the assembly name does not tie exactly with the namespace)
37 | /// The namespace containing types to be used
38 | public Reflector(string an, string ns)
39 | {
40 | m_ns = ns;
41 | m_asmb = null;
42 | foreach (AssemblyName aN in Assembly.GetExecutingAssembly().GetReferencedAssemblies())
43 | {
44 | if (aN.FullName.StartsWith(an))
45 | {
46 | m_asmb = Assembly.Load(aN);
47 | break;
48 | }
49 | }
50 | }
51 |
52 | #endregion
53 |
54 | #region Methods
55 |
56 | ///
57 | /// Return a Type instance for a type 'typeName'
58 | ///
59 | /// The name of the type
60 | /// A type instance
61 | public Type GetType(string typeName)
62 | {
63 | Type type = null;
64 | string[] names = typeName.Split('.');
65 |
66 | if (names.Length > 0)
67 | type = m_asmb.GetType(m_ns + "." + names[0]);
68 |
69 | for (int i = 1; i < names.Length; ++i) {
70 | type = type.GetNestedType(names[i], BindingFlags.NonPublic);
71 | }
72 | return type;
73 | }
74 |
75 | ///
76 | /// Create a new object of a named type passing along any params
77 | ///
78 | /// The name of the type to create
79 | ///
80 | /// An instantiated type
81 | public object New(string name, params object[] parameters)
82 | {
83 | Type type = GetType(name);
84 |
85 | ConstructorInfo[] ctorInfos = type.GetConstructors();
86 | foreach (ConstructorInfo ci in ctorInfos) {
87 | try {
88 | return ci.Invoke(parameters);
89 | } catch { }
90 | }
91 |
92 | return null;
93 | }
94 |
95 | ///
96 | /// Calls method 'func' on object 'obj' passing parameters 'parameters'
97 | ///
98 | /// The object on which to excute function 'func'
99 | /// The function to execute
100 | /// The parameters to pass to function 'func'
101 | /// The result of the function invocation
102 | public object Call(object obj, string func, params object[] parameters)
103 | {
104 | return Call2(obj, func, parameters);
105 | }
106 |
107 | ///
108 | /// Calls method 'func' on object 'obj' passing parameters 'parameters'
109 | ///
110 | /// The object on which to excute function 'func'
111 | /// The function to execute
112 | /// The parameters to pass to function 'func'
113 | /// The result of the function invocation
114 | public object Call2(object obj, string func, object[] parameters)
115 | {
116 | return CallAs2(obj.GetType(), obj, func, parameters);
117 | }
118 |
119 | ///
120 | /// Calls method 'func' on object 'obj' which is of type 'type' passing parameters 'parameters'
121 | ///
122 | /// The type of 'obj'
123 | /// The object on which to excute function 'func'
124 | /// The function to execute
125 | /// The parameters to pass to function 'func'
126 | /// The result of the function invocation
127 | public object CallAs(Type type, object obj, string func, params object[] parameters)
128 | {
129 | return CallAs2(type, obj, func, parameters);
130 | }
131 |
132 | ///
133 | /// Calls method 'func' on object 'obj' which is of type 'type' passing parameters 'parameters'
134 | ///
135 | /// The type of 'obj'
136 | /// The object on which to excute function 'func'
137 | /// The function to execute
138 | /// The parameters to pass to function 'func'
139 | /// The result of the function invocation
140 | public object CallAs2(Type type, object obj, string func, object[] parameters) {
141 | MethodInfo methInfo = type.GetMethod(func, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
142 | return methInfo.Invoke(obj, parameters);
143 | }
144 |
145 | ///
146 | /// Returns the value of property 'prop' of object 'obj'
147 | ///
148 | /// The object containing 'prop'
149 | /// The property name
150 | /// The property value
151 | public object Get(object obj, string prop)
152 | {
153 | return GetAs(obj.GetType(), obj, prop);
154 | }
155 |
156 | ///
157 | /// Returns the value of property 'prop' of object 'obj' which has type 'type'
158 | ///
159 | /// The type of 'obj'
160 | /// The object containing 'prop'
161 | /// The property name
162 | /// The property value
163 | public object GetAs(Type type, object obj, string prop) {
164 | PropertyInfo propInfo = type.GetProperty(prop, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
165 | return propInfo.GetValue(obj, null);
166 | }
167 |
168 | ///
169 | /// Returns an enum value
170 | ///
171 | /// The name of enum type
172 | /// The name of the value
173 | /// The enum value
174 | public object GetEnum(string typeName, string name) {
175 | Type type = GetType(typeName);
176 | FieldInfo fieldInfo = type.GetField(name);
177 | return fieldInfo.GetValue(null);
178 | }
179 |
180 | #endregion
181 |
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/mfs_gui/Icons/BlueDisk.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/BlueDisk.ico
--------------------------------------------------------------------------------
/mfs_gui/Icons/BlueDisk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/BlueDisk.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Filetypes/CARD.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Filetypes/CARD.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Filetypes/CRSD.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Filetypes/CRSD.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Filetypes/File.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Filetypes/File.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Filetypes/GSBLK.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Filetypes/GSBLK.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Filetypes/GSEXP.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Filetypes/GSEXP.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Filetypes/MA2D1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Filetypes/MA2D1.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Filetypes/MA3D1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Filetypes/MA3D1.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Filetypes/OPT.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Filetypes/OPT.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Filetypes/PSDNS.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Filetypes/PSDNS.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Filetypes/PSMAS.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Filetypes/PSMAS.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Filetypes/PSPPM.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Filetypes/PSPPM.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Filetypes/PSSEA.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Filetypes/PSSEA.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Filetypes/TSANL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Filetypes/TSANL.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Filetypes/TSANM.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Filetypes/TSANM.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Filetypes/TSBGA.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Filetypes/TSBGA.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Filetypes/TSBGL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Filetypes/TSBGL.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Filetypes/TSTLL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Filetypes/TSTLL.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Filetypes/TSTLT.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Filetypes/TSTLT.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/GreyDisk16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/GreyDisk16.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Storage/00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Storage/00.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Storage/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Storage/01.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Storage/02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Storage/02.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Storage/03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Storage/03.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Storage/04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Storage/04.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Storage/05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Storage/05.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Storage/06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Storage/06.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Storage/07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Storage/07.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Storage/08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Storage/08.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Storage/09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Storage/09.png
--------------------------------------------------------------------------------
/mfs_gui/Icons/Storage/10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuigiBlood/mfs_manager/daa58a829df986d2a77fabfc148e60504d771798/mfs_gui/Icons/Storage/10.png
--------------------------------------------------------------------------------
/mfs_gui/MainForm.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 | using FolderSelect;
12 | using mfs_library;
13 | using static System.Net.WebRequestMethods;
14 |
15 | namespace mfs_gui
16 | {
17 | public partial class MainForm : Form
18 | {
19 | enum cliptype
20 | {
21 | Copy, Cut
22 | }
23 |
24 | MFSDirectory current_dir;
25 | MFSFile[] clipboardfiles;
26 | cliptype clipboardtype;
27 | bool changed;
28 |
29 | public MainForm()
30 | {
31 | InitializeComponent();
32 | }
33 |
34 | private void openToolStripMenuItem_Click(object sender, EventArgs e)
35 | {
36 | OpenFileDialog ofs = new OpenFileDialog();
37 | ofs.Filter = "All Supported Files (*.ndd, *.ndr, *.ram, *.n64, *.z64, *.disk)|*.ndd;*.ndr;*.ram;*.n64;*.z64;*.disk|64DD RAM Area Image (*.ram)|*.ram|64DD Disk Image (*.ndd, *.ndr, *.disk)|*.ndd;*.ndr;*.disk|N64 Cartridge Port Image (*.n64, *.z64)|*.n64;*.z64|All files|*.*";
38 | ofs.Title = "Open Disk Image...";
39 | ofs.Multiselect = false;
40 | if (ofs.ShowDialog() == DialogResult.OK)
41 | {
42 | if (Program.LoadDisk(ofs.FileName))
43 | {
44 | treeViewMFS.Nodes.Clear();
45 | listViewMFS.Items.Clear();
46 |
47 | current_dir = null;
48 | clipboardfiles = null;
49 |
50 | TreeNode node;
51 | if (Program.GetDirectoryNode(out node))
52 | {
53 | treeViewMFS.Nodes.Add(node);
54 | treeViewMFS.Nodes[0].Expand();
55 | treeViewMFS.SelectedNode = treeViewMFS.Nodes[0];
56 | }
57 | }
58 | else
59 | {
60 | MessageBox.Show("Could not load " + ofs.SafeFileName, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
61 | }
62 | UpdateFormText();
63 | UpdateStatusBar();
64 | }
65 | }
66 |
67 | private void saveToolStripMenuItem_Click(object sender, EventArgs e)
68 | {
69 | if (Program.IsDiskLoaded())
70 | {
71 | Program.SaveDisk();
72 | changed = false;
73 | }
74 | UpdateFormText();
75 | }
76 |
77 | private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
78 | {
79 | if (!Program.IsDiskLoaded())
80 | return;
81 |
82 | SaveFileDialog sfd = new SaveFileDialog();
83 | sfd.Title = "Save as...";
84 | if (sfd.ShowDialog() == DialogResult.OK)
85 | {
86 | Program.SaveDisk(sfd.FileName);
87 | changed = false;
88 | }
89 | UpdateFormText();
90 | }
91 |
92 | private void exitToolStripMenuItem_Click(object sender, EventArgs e)
93 | {
94 | Application.Exit();
95 | }
96 |
97 | private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
98 | {
99 | MessageBox.Show("64DD MFS Manager (GUI) " + Application.ProductVersion + " by LuigiBlood", "About...", MessageBoxButtons.OK, MessageBoxIcon.Information);
100 | }
101 |
102 | private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
103 | {
104 | if (changed && MessageBox.Show("Are you sure you want to exit 64DD MFS Manager?\nYour changes will be lost.", "Exit", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
105 | e.Cancel = true;
106 | }
107 |
108 | private void treeView_AfterSelect(object sender, TreeViewEventArgs e)
109 | {
110 | current_dir = (MFSDirectory)e.Node.Tag;
111 | UpdateTreeView(current_dir);
112 | }
113 |
114 | private void listView_DragEnter(object sender, DragEventArgs e)
115 | {
116 | e.Effect = DragDropEffects.None;
117 | if (current_dir != null)
118 | e.Effect = DragDropEffects.Copy;
119 | }
120 |
121 | private void listView_DragDrop(object sender, DragEventArgs e)
122 | {
123 | string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
124 | Program.AddFilesToDirectory(current_dir, files);
125 | UpdateTreeView(current_dir);
126 | changed = true;
127 | UpdateFormText();
128 | }
129 |
130 | private void contextMenuStripFile_Opening(object sender, CancelEventArgs e)
131 | {
132 | foreach (ToolStripItem test in contextMenuStripFile.Items)
133 | {
134 | test.Enabled = false;
135 | }
136 | if (listViewMFS.SelectedItems.Count > 0)
137 | {
138 | extractToolStripMenuItem.Enabled = true;
139 | cutToolStripMenuItem.Enabled = true;
140 | copyToolStripMenuItem.Enabled = true;
141 | deleteToolStripMenuItem.Enabled = true;
142 | if (listViewMFS.SelectedItems.Count == 1)
143 | renameToolStripMenuItem.Enabled = true;
144 |
145 | List files = new List();
146 | foreach (ListViewItem item in listViewMFS.SelectedItems)
147 | {
148 | files.Add(((MFSFile)item.Tag).GetEntryName());
149 | }
150 | if (Program.CanExportConvertFiles(files.ToArray()))
151 | {
152 | convertFilesToolStripMenuItem.Enabled = true;
153 | }
154 |
155 | }
156 | if (current_dir != null)
157 | importToolStripMenuItem.Enabled = true;
158 | if (clipboardfiles != null && clipboardfiles.Length > 0)
159 | pasteToolStripMenuItem.Enabled = true;
160 | }
161 |
162 | private void importToolStripMenuItem_Click(object sender, EventArgs e)
163 | {
164 | OpenFileDialog ofs = new OpenFileDialog();
165 | ofs.Filter = "All files|*.*";
166 | ofs.Title = "Import Files...";
167 | ofs.Multiselect = true;
168 |
169 | if (ofs.ShowDialog() == DialogResult.OK)
170 | {
171 | string[] files = ofs.FileNames;
172 | Program.AddFilesToDirectory(current_dir, files);
173 | UpdateTreeView(current_dir);
174 | changed = true;
175 | UpdateFormText();
176 | }
177 | }
178 |
179 | private void extractToolStripMenuItem_Click(object sender, EventArgs e)
180 | {
181 | if (listViewMFS.SelectedItems.Count > 1)
182 | {
183 | //More than one file
184 | FolderSelectDialog fsd = new FolderSelectDialog();
185 | fsd.Title = "Export Files...";
186 | if (fsd.ShowDialog())
187 | {
188 | List files = new List();
189 | foreach (ListViewItem item in listViewMFS.SelectedItems)
190 | {
191 | files.Add((MFSFile)item.Tag);
192 | }
193 | if (Program.SaveFiles(files.ToArray(), fsd.FileName))
194 | MessageBox.Show("Files are extracted successfully.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
195 | }
196 | }
197 | else if (listViewMFS.SelectedItems.Count == 1)
198 | {
199 | //Only one file
200 | MFSFile file = (MFSFile)listViewMFS.SelectedItems[0].Tag;
201 | SaveFileDialog sfd = new SaveFileDialog();
202 | sfd.Title = "Export File...";
203 | sfd.FileName = file.Name + (file.Ext != "" ? "." + file.Ext : "");
204 | if (sfd.ShowDialog() == DialogResult.OK)
205 | {
206 | if (Program.SaveFile(file, sfd.FileName))
207 | MessageBox.Show("File is extracted successfully.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
208 | }
209 | }
210 | }
211 |
212 | private void convertFilesToolStripMenuItem_Click(object sender, EventArgs e)
213 | {
214 | if (listViewMFS.SelectedItems.Count > 1)
215 | {
216 | //More than one file
217 | FolderSelectDialog fsd = new FolderSelectDialog();
218 | fsd.Title = "Convert File(s)...";
219 | if (fsd.ShowDialog())
220 | {
221 | List files = new List();
222 | foreach (ListViewItem item in listViewMFS.SelectedItems)
223 | {
224 | files.Add((MFSFile)item.Tag);
225 | }
226 | if (Program.ExportConvertFiles(files.ToArray(), fsd.FileName))
227 | MessageBox.Show("Files are converted successfully.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
228 | }
229 | }
230 | else if (listViewMFS.SelectedItems.Count == 1)
231 | {
232 | //Only one file
233 | MFSFile file = (MFSFile)listViewMFS.SelectedItems[0].Tag;
234 | if (!Program.CanExportConvertFile(file.GetEntryName()))
235 | {
236 | return;
237 | }
238 | SaveFileDialog sfd = new SaveFileDialog();
239 | sfd.Title = "Convert File...";
240 | sfd.FileName = file.GetEntryName() + ".png";
241 | sfd.Filter = "Image File (*.png)|*.png";
242 | if (sfd.ShowDialog() == DialogResult.OK)
243 | {
244 | if (Program.ExportConvertFile(file, sfd.FileName))
245 | MessageBox.Show("File is converted successfully.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
246 | }
247 | }
248 | }
249 |
250 | private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
251 | {
252 | if (listViewMFS.SelectedItems.Count > 0)
253 | {
254 | List files = new List();
255 | foreach (ListViewItem item in listViewMFS.SelectedItems)
256 | {
257 | files.Add((MFSFile)item.Tag);
258 | }
259 | Program.DeleteFiles(files.ToArray());
260 | UpdateTreeView(current_dir);
261 | changed = true;
262 | UpdateFormText();
263 | }
264 | }
265 |
266 | private void cutToolStripMenuItem_Click(object sender, EventArgs e)
267 | {
268 | List files = new List();
269 | foreach (ListViewItem item in listViewMFS.SelectedItems)
270 | {
271 | files.Add((MFSFile)item.Tag);
272 | }
273 |
274 | clipboardfiles = files.ToArray();
275 | clipboardtype = cliptype.Cut;
276 | }
277 |
278 | private void copyToolStripMenuItem_Click(object sender, EventArgs e)
279 | {
280 | List files = new List();
281 | foreach (ListViewItem item in listViewMFS.SelectedItems)
282 | {
283 | files.Add((MFSFile)item.Tag);
284 | }
285 |
286 | clipboardfiles = files.ToArray();
287 | clipboardtype = cliptype.Copy;
288 | }
289 |
290 | private void pasteToolStripMenuItem_Click(object sender, EventArgs e)
291 | {
292 | if (clipboardtype == cliptype.Copy)
293 | Program.CopyFiles(clipboardfiles, current_dir.DirectoryID);
294 | else
295 | Program.MoveFiles(clipboardfiles, current_dir.DirectoryID);
296 | UpdateTreeView(current_dir);
297 | changed = true;
298 | UpdateFormText();
299 | }
300 |
301 | private void renameToolStripMenuItem_Click(object sender, EventArgs e)
302 | {
303 | if (listViewMFS.SelectedItems.Count == 1)
304 | {
305 | listViewMFS.SelectedItems[0].BeginEdit();
306 | }
307 | }
308 |
309 | private void listView_AfterLabelEdit(object sender, LabelEditEventArgs e)
310 | {
311 | MFSFile file = (MFSFile)listViewMFS.Items[e.Item].Tag;
312 | if (e.Label != null)
313 | {
314 | string _name = Path.GetFileNameWithoutExtension(e.Label);
315 | string _ext = Path.GetExtension(e.Label);
316 | if (_ext.StartsWith("."))
317 | _ext = _ext.Substring(1);
318 |
319 | if (file.Ext != _ext)
320 | {
321 | if (MessageBox.Show("Are you sure to change the extension of the file? It may not work as intended.", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No)
322 | return;
323 | changed = true;
324 | }
325 |
326 | if (file.Name != _name)
327 | changed = true;
328 |
329 | file.Ext = _ext;
330 | file.Name = _name;
331 | }
332 | UpdateTreeView(current_dir);
333 | UpdateFormText();
334 | }
335 |
336 | //Other
337 | private void UpdateTreeView(MFSDirectory dir)
338 | {
339 | ListViewItem[] items;
340 | listViewMFS.Items.Clear();
341 | if (Program.GetAllFilesFromDirectory(dir, out items))
342 | {
343 | listViewMFS.Items.AddRange(items);
344 | }
345 | UpdateStatusBar();
346 | }
347 |
348 | private void UpdateStatusBar()
349 | {
350 | statusStrip1.Items.Clear();
351 | if (Program.IsDiskLoaded())
352 | {
353 | statusStrip1.Items.Add("Free Space: " + Math.Floor((Program.GetCapacitySize() - Program.GetUsedSpaceSize()) / 100000f) / 10f + " MB");
354 | }
355 | }
356 |
357 | private void UpdateFormText()
358 | {
359 | if (Program.IsDiskLoaded())
360 | {
361 | this.Text = "64DD MFS Manager - " + (changed ? "*" : "") + "[" + Program.GetDiskFilename() + "]";
362 | }
363 | else
364 | {
365 | this.Text = "64DD MFS Manager";
366 | }
367 | }
368 | }
369 | }
370 |
--------------------------------------------------------------------------------
/mfs_gui/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.IO;
5 | using System.Threading.Tasks;
6 | using System.Windows.Forms;
7 | using mfs_library;
8 | using System.Drawing;
9 |
10 | namespace mfs_gui
11 | {
12 | static class Program
13 | {
14 | static MainForm mainform;
15 | static string loadedfilepath;
16 | static MFSDisk disk;
17 |
18 | static char[] symbolsContainer = { '♦', '■', '●', '♥', '♠', '♣', '▼', '♪', '▲', '★' };
19 |
20 | [STAThread]
21 | static void Main()
22 | {
23 | Application.EnableVisualStyles();
24 | Application.SetCompatibleTextRenderingDefault(false);
25 | mainform = new MainForm();
26 | Application.Run(mainform);
27 | }
28 |
29 | public static bool IsDiskLoaded()
30 | {
31 | if (disk == null) return false;
32 | return (disk.Disk.RAMFileSystem == LeoDisk.FileSystem.MFS);
33 | }
34 |
35 | public static string GetDiskFilename()
36 | {
37 | return loadedfilepath;
38 | }
39 |
40 | public static bool LoadDisk(string filepath)
41 | {
42 | MFSDisk disk_temp = new MFSDisk(filepath);
43 | if (disk_temp.Disk.RAMFileSystem == LeoDisk.FileSystem.MFS)
44 | {
45 | loadedfilepath = filepath;
46 | disk = disk_temp;
47 | return true;
48 | }
49 | return false;
50 | }
51 |
52 | public static bool SaveDisk(string filepath = "")
53 | {
54 | if (disk == null || disk.Disk.Format == LeoDisk.DiskFormat.Invalid)
55 | return false;
56 |
57 | if (filepath == "")
58 | filepath = loadedfilepath;
59 |
60 | disk.Save(filepath);
61 |
62 | loadedfilepath = filepath;
63 | return true;
64 | }
65 |
66 | public static bool GetDirectoryNode(out TreeNode nodes)
67 | {
68 | nodes = new TreeNode();
69 | if (disk == null || disk.Disk.Format == LeoDisk.DiskFormat.Invalid)
70 | return false;
71 |
72 | nodes = GetDirectoryTreeNode(MFSRAMUtil.GetDirectoryFromID(disk, 0));
73 | nodes.ImageIndex = 0;
74 | nodes.SelectedImageIndex = 0;
75 | return true;
76 | }
77 |
78 | static TreeNode GetDirectoryTreeNode(MFSDirectory pdir)
79 | {
80 | TreeNode node = new TreeNode(pdir.Name);
81 | node.Tag = pdir;
82 | node.ImageIndex = GetContainerColor(pdir.Name);
83 | node.SelectedImageIndex = node.ImageIndex;
84 | foreach (MFSDirectory dir in MFSRAMUtil.GetAllDirectoriesFromDirID(disk, pdir.DirectoryID))
85 | {
86 | node.Nodes.Add(GetDirectoryTreeNode(dir));
87 | }
88 | return node;
89 | }
90 |
91 | static int GetContainerColor(string name)
92 | {
93 | foreach (char c in name)
94 | {
95 | for (int i = 0; i < symbolsContainer.Length; i++)
96 | if (c == symbolsContainer[i]) return i + 2;
97 | }
98 | return 1;
99 | }
100 |
101 | public static bool GetAllFilesFromDirectory(MFSDirectory dir, out ListViewItem[] items)
102 | {
103 | List list = new List();
104 | if (disk == null || disk.Disk.Format == LeoDisk.DiskFormat.Invalid)
105 | {
106 | items = null;
107 | return false;
108 | }
109 |
110 | foreach (MFSFile file in MFSRAMUtil.GetAllFilesFromDirID(disk, dir.DirectoryID))
111 | {
112 | ListViewItem item = new ListViewItem(file.Name + (file.Ext != "" ? "." + file.Ext : ""));
113 | item.Tag = file;
114 | item.ImageIndex = mainform.imageListLarge.Images.IndexOfKey(file.Ext);
115 | if (item.ImageIndex == -1)
116 | item.ImageIndex = 0;
117 | list.Add(item);
118 | }
119 |
120 | items = list.ToArray();
121 | return true;
122 | }
123 |
124 | public static bool AddFileToDirectory(MFSDirectory dir, string filepath)
125 | {
126 | if (disk == null || disk.Disk.Format == LeoDisk.DiskFormat.Invalid)
127 | {
128 | return false;
129 | }
130 |
131 | bool error;
132 | if (!CanImportConvertFile(filepath))
133 | {
134 | byte[] filedata = File.ReadAllBytes(filepath);
135 | error = MFSRAMUtil.WriteFile(disk, filedata, Path.GetFileName(filepath), dir.DirectoryID);
136 | }
137 | else
138 | {
139 | byte[] filedata;
140 | string filename;
141 |
142 | if (ImportConvertFile(filepath, out filedata, out filename))
143 | {
144 | error = MFSRAMUtil.WriteFile(disk, filedata, filename, dir.DirectoryID);
145 | }
146 | else
147 | {
148 | error = false;
149 | }
150 | }
151 |
152 | return error;
153 | }
154 |
155 | public static bool AddFilesToDirectory(MFSDirectory dir, string[] filepaths)
156 | {
157 | foreach (string file in filepaths)
158 | {
159 | if (Program.AddFileToDirectory(dir, file) == false)
160 | {
161 | MessageBox.Show("Could not import " + Path.GetFileName(file) + "\nCancelling file import.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
162 | break;
163 | }
164 | }
165 | return true;
166 | }
167 |
168 | public static bool ImportConvertFile(string filepath, out byte[] bytes, out string filename)
169 | {
170 | if (!CanImportConvertFile(filepath))
171 | {
172 | bytes = null;
173 | filename = null;
174 | return false;
175 | }
176 |
177 | Bitmap input = new Bitmap(filepath);
178 |
179 | bytes = mfs_library.MA.MA2D1.ConvertToMA2D1(input);
180 | filename = Path.GetFileNameWithoutExtension(filepath) + ".MA2D1";
181 |
182 | input.Dispose();
183 |
184 | return true;
185 | }
186 |
187 | public static bool CanImportConvertFile(string filepath)
188 | {
189 | switch (Path.GetExtension(filepath).ToLower())
190 | {
191 | case ".png":
192 | case ".bmp":
193 | case ".jpg":
194 | case ".jpeg":
195 | return true;
196 | }
197 | return false;
198 | }
199 |
200 | public static bool CanImportConvertFiles(string[] filepaths)
201 | {
202 | foreach (string s in filepaths)
203 | {
204 | switch (Path.GetExtension(s).ToLower())
205 | {
206 | case ".png":
207 | case ".bmp":
208 | case ".jpg":
209 | case ".jpeg":
210 | return true;
211 | }
212 | }
213 | return false;
214 | }
215 |
216 | public static bool ExportConvertFile(MFSFile file, string filepath)
217 | {
218 | if (!CanExportConvertFile(file.GetEntryName())) return false;
219 |
220 | var input = LoadFileData(file);
221 |
222 | Bitmap output = mfs_library.MA.MA2D1.ConvertToBitmap(input);
223 | output.Save(filepath);
224 | output.Dispose();
225 | return true;
226 | }
227 |
228 | public static bool ExportConvertFiles(MFSFile[] file, string folderpath)
229 | {
230 | foreach (MFSFile f in file)
231 | {
232 | ExportConvertFile(f, folderpath + "\\" + f.GetEntryName() + ".png");
233 | }
234 | return true;
235 | }
236 |
237 | public static bool CanExportConvertFile(string filepath)
238 | {
239 | switch (Path.GetExtension(filepath).ToLower())
240 | {
241 | case ".ma2d1":
242 | return true;
243 | }
244 | return false;
245 | }
246 |
247 | public static bool CanExportConvertFiles(string[] filepaths)
248 | {
249 | foreach (string s in filepaths)
250 | {
251 | switch (Path.GetExtension(s).ToLower())
252 | {
253 | case ".ma2d1":
254 | return true;
255 | }
256 | }
257 | return false;
258 | }
259 |
260 | public static byte[] LoadFileData(MFSFile file)
261 | {
262 | return MFSRAMUtil.ReadFile(disk, file);
263 | }
264 |
265 | public static bool SaveFiles(MFSFile[] files, string folderpath)
266 | {
267 | if (disk == null || disk.Disk.Format == LeoDisk.DiskFormat.Invalid)
268 | {
269 | return false;
270 | }
271 |
272 | foreach (MFSFile file in files)
273 | {
274 | byte[] filedata = MFSRAMUtil.ReadFile(disk, file);
275 | FileStream fileout = new FileStream(folderpath + "\\" + file.Name + (file.Ext != "" ? "." + file.Ext : ""), FileMode.Create);
276 | fileout.Write(filedata, 0, filedata.Length);
277 | fileout.Close();
278 | }
279 | return true;
280 | }
281 |
282 | public static bool DeleteFiles(MFSFile[] files)
283 | {
284 | if (disk == null || disk.Disk.Format == LeoDisk.DiskFormat.Invalid)
285 | {
286 | return false;
287 | }
288 |
289 | foreach (MFSFile file in files)
290 | {
291 | MFSRAMUtil.DeleteFile(disk, file);
292 | }
293 | return true;
294 | }
295 |
296 | public static bool SaveFile(MFSFile file, string filepath)
297 | {
298 | if (disk == null || disk.Disk.Format == LeoDisk.DiskFormat.Invalid)
299 | {
300 | return false;
301 | }
302 |
303 | byte[] filedata = MFSRAMUtil.ReadFile(disk, file);
304 | FileStream fileout = new FileStream(filepath, FileMode.Create);
305 | fileout.Write(filedata, 0, filedata.Length);
306 | fileout.Close();
307 |
308 | return true;
309 | }
310 |
311 | public static bool CopyFiles(MFSFile[] files, ushort dir)
312 | {
313 | if (disk == null || disk.Disk.Format == LeoDisk.DiskFormat.Invalid)
314 | {
315 | return false;
316 | }
317 |
318 | foreach (MFSFile file in files)
319 | {
320 | MFSRAMUtil.WriteFile(disk, MFSRAMUtil.ReadFile(disk, file), file.Name + (file.Ext != "" ? "." + file.Ext : ""), dir);
321 | }
322 |
323 | return true;
324 | }
325 |
326 | public static bool MoveFiles(MFSFile[] files, ushort dir)
327 | {
328 | if (disk == null || disk.Disk.Format == LeoDisk.DiskFormat.Invalid)
329 | {
330 | return false;
331 | }
332 |
333 | foreach (MFSFile file in files)
334 | {
335 | MFSRAMUtil.MoveFile(disk, MFSRAMUtil.GetFullPath(disk, file), MFSRAMUtil.GetFullPath(disk, MFSRAMUtil.GetDirectoryFromID(disk, dir)));
336 | }
337 |
338 | return true;
339 | }
340 |
341 | public static int GetCapacitySize()
342 | {
343 | return MFSRAMUtil.GetCapacitySize(disk);
344 | }
345 |
346 | public static int GetUsedSpaceSize()
347 | {
348 | return MFSRAMUtil.GetTotalUsedSize(disk);
349 | }
350 | }
351 | }
352 |
--------------------------------------------------------------------------------
/mfs_gui/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // Les informations générales relatives à un assembly dépendent de
6 | // l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations
7 | // associées à un assembly.
8 | [assembly: AssemblyTitle("64DD MFS Manager (GUI)")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("64DD MFS Manager (GUI)")]
13 | [assembly: AssemblyCopyright("Copyright © LuigiBlood 2019")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly
18 | // aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de
19 | // COM, affectez la valeur true à l'attribut ComVisible sur ce type.
20 | [assembly: ComVisible(false)]
21 |
22 | // Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM
23 | [assembly: Guid("48ec8983-43d6-4686-b33d-fd46fec8ce8d")]
24 |
25 | // Les informations de version pour un assembly se composent des quatre valeurs suivantes :
26 | //
27 | // Version principale
28 | // Version secondaire
29 | // Numéro de build
30 | // Révision
31 | //
32 | // Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut
33 | // en utilisant '*', comme indiqué ci-dessous :
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.3.0.0")]
36 | [assembly: AssemblyFileVersion("1.3.0.0")]
37 |
--------------------------------------------------------------------------------
/mfs_gui/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // Ce code a été généré par un outil.
4 | // Version du runtime :4.0.30319.42000
5 | //
6 | // Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si
7 | // le code est régénéré.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace mfs_gui.Properties
12 | {
13 |
14 |
15 | ///
16 | /// Une classe de ressource fortement typée destinée, entre autres, à la consultation des chaînes localisées.
17 | ///
18 | // Cette classe a été générée automatiquement par la classe StronglyTypedResourceBuilder
19 | // à l'aide d'un outil, tel que ResGen ou Visual Studio.
20 | // Pour ajouter ou supprimer un membre, modifiez votre fichier .ResX, puis réexécutez ResGen
21 | // avec l'option /str ou régénérez votre projet VS.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// Retourne l'instance ResourceManager mise en cache utilisée par cette classe.
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("mfs_gui.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// Remplace la propriété CurrentUICulture du thread actuel pour toutes
56 | /// les recherches de ressources à l'aide de cette classe de ressource fortement typée.
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/mfs_gui/Properties/Resources.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 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/mfs_gui/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace mfs_gui.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/mfs_gui/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/mfs_gui/changelog.txt:
--------------------------------------------------------------------------------
1 | 64DD MFS Manager
2 |
3 | Changelog:
4 | v1.3.0.0:
5 | - mfs_library: Refactored a lot of classes and other processes
6 | - mfs_library: Add MA2D1 Image conversion
7 | - mfs_manager: Add check for MFS Filesystem
8 | - mfs_gui: Do not unload/reload when you try to load another disk
9 | - mfs_gui: Add automatic image import conversion
10 | - mfs_gui: Add image export conversion
11 | - save_manager: Added
12 |
13 | v1.2.1.1:
14 | - mfs_library: Fix off-by-one error that prevents reading the last LBA of the disk
15 |
16 | v1.2.1.0:
17 | - mfs_library: Create library using mfs_manager functions and refactoring.
18 | - mfs_library: Seperate Disk management from MFSDisk class into its own class (LeoDisk).
19 | - mfs_library: Fix offset calculation with MAME Disk format access (Critical)
20 | - mfs_manager: Process extension change based on filename and extension.
21 |
22 | v1.2.0.0:
23 | - Support MAME format disk images (used by Ares for saves)
24 | - Rudimentary code to keep track of changes for saving and also to only provide a prompt when exiting if the changes were not saved.
25 |
26 | v0.0.3.1:
27 | - Add forgotten N64 Cartridge Port support to the File Loading window
28 |
29 | v0.0.3.0:
30 | - Fixed locked Drag & Drop import after loading a disk.
31 | - Added Import option into the right click menu.
32 | - Show Free Space size on status bar.
33 | - Warn when files cannot be imported.
34 |
35 | v0.0.2.0:
36 | - Cartridge Port ROM support
37 |
38 | v0.0.1.0:
39 | - Initial release
40 |
--------------------------------------------------------------------------------
/mfs_gui/license.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | mfs_manager
4 | Copyright (c) 2019 LuigiBlood
5 |
6 | Mr-Peeps-Compressor
7 | Copyright (c) 2017 Dan McCarthy
8 |
9 | Permission is hereby granted, free of charge, to any person obtaining a copy
10 | of this software and associated documentation files (the "Software"), to deal
11 | in the Software without restriction, including without limitation the rights
12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | copies of the Software, and to permit persons to whom the Software is
14 | furnished to do so, subject to the following conditions:
15 |
16 | The above copyright notice and this permission notice shall be included in all
17 | copies or substantial portions of the Software.
18 |
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | SOFTWARE.
26 |
--------------------------------------------------------------------------------
/mfs_gui/mfs_gui.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {48EC8983-43D6-4686-B33D-FD46FEC8CE8D}
8 | WinExe
9 | mfs_gui
10 | mfs_gui
11 | v4.6.1
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 |
37 |
38 |
39 |
40 | Icons\BlueDisk.ico
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | Form
60 |
61 |
62 | MainForm.cs
63 |
64 |
65 |
66 |
67 | MainForm.cs
68 |
69 |
70 | ResXFileCodeGenerator
71 | Resources.Designer.cs
72 | Designer
73 |
74 |
75 | True
76 | Resources.resx
77 |
78 |
79 | SettingsSingleFileGenerator
80 | Settings.Designer.cs
81 |
82 |
83 | True
84 | Settings.settings
85 | True
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 | Always
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 | Always
128 |
129 |
130 | Always
131 |
132 |
133 |
134 |
135 | False
136 | Microsoft .NET Framework 4.6.1 %28x86 et x64%29
137 | true
138 |
139 |
140 | False
141 | .NET Framework 3.5 SP1
142 | false
143 |
144 |
145 |
146 |
147 | {8d1cf3e5-ba0f-4790-ba0a-c52b79302da3}
148 | mfs_library
149 |
150 |
151 |
152 |
--------------------------------------------------------------------------------
/mfs_gui/readme.txt:
--------------------------------------------------------------------------------
1 | 64DD MFS Manager v1.3.0.0
2 |
3 | This contains the following:
4 | - mfs_library: the main library for disk and MFS access
5 | - mfs_manager: the command line utility project
6 | - mfs_gui: the user friendly utility
7 | - save_manager: basic RAW import/export of disk RAM area
8 |
9 |
10 | This software can be used to manage files in 64DD titles that uses MFS for save data. You can import, extract, copy, move and rename files.
11 | Supports *.ndd disk images (64DD Dump Tool), *.disk (MAME 64DD disk image format), and *.ram (Pure 64DD disk RAM Partition image).
12 |
13 | Use at your own risk.
14 |
15 | The only known titles to use MFS are:
16 | - Mario Artist Paint Studio
17 | - Mario Artist Talent Studio
18 | - Mario Artist Communication Kit
19 | - Mario Artist Polygon Studio
20 | - Japan Pro Golf Tour 64 (do not delete zero3MByte.dat)
21 | - F-Zero X Expansion Kit
22 | - Randnet Disk
23 |
24 | Watch out to make sure to use the proper directories for save management.
25 |
26 |
27 | Important Notices:
28 | - When you import BMP, PNG, or JPG files, it is automatically converted and resized to 216x202 MA2D1 files (2D picture format for Mario Artist).
29 |
--------------------------------------------------------------------------------
/mfs_library/Leo/Leo.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 mfs_library
8 | {
9 | public static class Leo
10 | {
11 | public const int MAX_LBA = 0x10DB;
12 | public const int SIZE_LBA = MAX_LBA + 1;
13 | public const int SYSTEM_LBAS = 24;
14 | public const int DISKID_LBA = 14;
15 |
16 | public const int SECTORS_PER_BLOCK = 85;
17 |
18 | public const int BLOCKS_PER_TRACK = 2;
19 |
20 | public const int DISK_SIZE_MAME = 0x435B0C0;
21 | public const int DISK_SIZE_SDK = 0x3DEC800;
22 |
23 | /* LBA to Disk System Data (Retail) */
24 | public static readonly int[] LBA_SYS_PROD = { 0, 1, 8, 9 };
25 |
26 | /* LBA to Disk System Data (Development) */
27 | public static readonly int[] LBA_SYS_DEV = { 2, 3, 10, 11 };
28 |
29 | /* Sector Size in bytes [zone] */
30 | public static readonly int[] SECTOR_SIZE = { 232, 216, 208, 192, 176, 160, 144, 128, 112 };
31 |
32 | /* Block Size in bytes [zone] */
33 | public static readonly int[] BLOCK_SIZE = { 0x4D08, 0x47B8, 0x4510, 0x3FC0, 0x3A70, 0x3520, 0x2FD0, 0x2A80, 0x2530 };
34 |
35 | /* Outer Track per Zone [zone] */
36 | static readonly int[] PZONE_TRACK = { 0x000, 0x09E, 0x13C, 0x1D1, 0x266, 0x2FB, 0x390, 0x425, 0x497 };
37 |
38 | /* Start Track of Zone [pzone] */
39 | static readonly int[] TRACK_START_ZONE_TBL =
40 | {0x000, 0x09E, 0x13C, 0x1D1, 0x266, 0x2FB, 0x390, 0x425,
41 | 0x091, 0x12F, 0x1C4, 0x259, 0x2EE, 0x383, 0x418, 0x48A};
42 |
43 | /* LBA to VZone [type,vzone] */
44 | static readonly int[,] VZONE_LBA_TBL = {
45 | {0x0124, 0x0248, 0x035A, 0x047E, 0x05A2, 0x06B4, 0x07C6, 0x08D8, 0x09EA, 0x0AB6, 0x0B82, 0x0C94, 0x0DA6, 0x0EB8, 0x0FCA, 0x10DC},
46 | {0x0124, 0x0248, 0x035A, 0x046C, 0x057E, 0x06A2, 0x07C6, 0x08D8, 0x09EA, 0x0AFC, 0x0BC8, 0x0C94, 0x0DA6, 0x0EB8, 0x0FCA, 0x10DC},
47 | {0x0124, 0x0248, 0x035A, 0x046C, 0x057E, 0x0690, 0x07A2, 0x08C6, 0x09EA, 0x0AFC, 0x0C0E, 0x0CDA, 0x0DA6, 0x0EB8, 0x0FCA, 0x10DC},
48 | {0x0124, 0x0248, 0x035A, 0x046C, 0x057E, 0x0690, 0x07A2, 0x08B4, 0x09C6, 0x0AEA, 0x0C0E, 0x0D20, 0x0DEC, 0x0EB8, 0x0FCA, 0x10DC},
49 | {0x0124, 0x0248, 0x035A, 0x046C, 0x057E, 0x0690, 0x07A2, 0x08B4, 0x09C6, 0x0AD8, 0x0BEA, 0x0D0E, 0x0E32, 0x0EFE, 0x0FCA, 0x10DC},
50 | {0x0124, 0x0248, 0x035A, 0x046C, 0x057E, 0x0690, 0x07A2, 0x086E, 0x0980, 0x0A92, 0x0BA4, 0x0CB6, 0x0DC8, 0x0EEC, 0x1010, 0x10DC},
51 | {0x0124, 0x0248, 0x035A, 0x046C, 0x057E, 0x0690, 0x07A2, 0x086E, 0x093A, 0x0A4C, 0x0B5E, 0x0C70, 0x0D82, 0x0E94, 0x0FB8, 0x10DC}
52 | };
53 |
54 | /* VZone to PZone [type,vzone] */
55 | static readonly int[,] VZONE_PZONE_TBL = {
56 | {0x0, 0x1, 0x2, 0x9, 0x8, 0x3, 0x4, 0x5, 0x6, 0x7, 0xF, 0xE, 0xD, 0xC, 0xB, 0xA},
57 | {0x0, 0x1, 0x2, 0x3, 0xA, 0x9, 0x8, 0x4, 0x5, 0x6, 0x7, 0xF, 0xE, 0xD, 0xC, 0xB},
58 | {0x0, 0x1, 0x2, 0x3, 0x4, 0xB, 0xA, 0x9, 0x8, 0x5, 0x6, 0x7, 0xF, 0xE, 0xD, 0xC},
59 | {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0xC, 0xB, 0xA, 0x9, 0x8, 0x6, 0x7, 0xF, 0xE, 0xD},
60 | {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0xD, 0xC, 0xB, 0xA, 0x9, 0x8, 0x7, 0xF, 0xE},
61 | {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0xE, 0xD, 0xC, 0xB, 0xA, 0x9, 0x8, 0xF},
62 | {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0xF, 0xE, 0xD, 0xC, 0xB, 0xA, 0x9, 0x8}
63 | };
64 |
65 | /* LBA Start RAM Area [type] */
66 | public static readonly short[] RamStartLBA = { 0x5A2, 0x7C6, 0x9EA, 0xC0E, 0xE32, 0x1010, 0x10DC };
67 |
68 | /* RAM Area Total Sizes [type] */
69 | public static readonly int[] RamSize = { 0x24A9DC0, 0x1C226C0, 0x1450F00, 0xD35680, 0x6CFD40, 0x1DA240, 0x0 };
70 |
71 | /* LBA To Virtual Zone */
72 | public static int LBAToVZone(int lba, int disktype)
73 | {
74 | for (int vzone = 0; vzone < 16; vzone++)
75 | {
76 | if (lba < VZONE_LBA_TBL[disktype,vzone])
77 | {
78 | return vzone;
79 | }
80 | }
81 | return -1;
82 | }
83 |
84 | /* Virtual Zone to Physical Zone */
85 | public static int VZoneToPZone(int vzone, int disktype) { return VZONE_PZONE_TBL[disktype, vzone]; }
86 |
87 | /* Calculate byte size from LBA x to LBA x+y */
88 | public static int LBAToByte(int disktype, int startlba, int nlbas)
89 | {
90 | if (disktype < 0 && disktype > 7) throw new ArgumentOutOfRangeException("Disk Type out of range", disktype.ToString());
91 | if (startlba < 0 && startlba > Leo.MAX_LBA) throw new ArgumentOutOfRangeException("LBA Start out of range", startlba.ToString());
92 | if (nlbas < 0 && nlbas > Leo.MAX_LBA) throw new ArgumentOutOfRangeException("LBA Amount out of range", nlbas.ToString());
93 | if ((startlba + nlbas) < 0 && (startlba + nlbas) > Leo.MAX_LBA) throw new ArgumentOutOfRangeException("LBA Start out of range", (startlba + nlbas).ToString());
94 |
95 | int totalbytes = 0;
96 | bool init_flag = true;
97 | int vzone = 1;
98 | int pzone = 0;
99 | int lba = startlba;
100 | int lba_count = nlbas;
101 | int blkbytes = 0;
102 | if (nlbas != 0)
103 | {
104 | for (; lba_count != 0; lba_count--)
105 | {
106 | if ((init_flag) || (VZONE_LBA_TBL[disktype, vzone] == lba))
107 | {
108 | vzone = LBAToVZone(lba, disktype);
109 | pzone = VZoneToPZone(vzone, disktype);
110 | if (7 < pzone)
111 | {
112 | pzone -= 7;
113 | }
114 | blkbytes = BLOCK_SIZE[pzone];
115 | }
116 | totalbytes += blkbytes;
117 | lba++;
118 | init_flag = false;
119 | if ((lba_count > 1) && (lba > MAX_LBA))
120 | {
121 | return -1;
122 | }
123 | }
124 | }
125 | return totalbytes;
126 | }
127 |
128 | /* MAME Disk Format Offsets for each zone */
129 | static readonly int[] MAMEOffsetTable =
130 | {0x0,0x5F15E0,0xB79D00,0x10801A0,0x1523720,0x1963D80,0x1D414C0,0x20BBCE0,
131 | 0x23196E0,0x28A1E00,0x2DF5DC0,0x3299340,0x36D99A0,0x3AB70E0,0x3E31900,0x4149200};
132 |
133 | public static int LBAToMAMEOffset(int lba, byte[] sysData)
134 | {
135 | if (lba < 0 && lba > Leo.MAX_LBA) throw new ArgumentOutOfRangeException("LBA out of range", lba.ToString());
136 |
137 | int head, track, block;
138 | LBAToPhys(lba, sysData, out head, out track, out block);
139 | return PhysToMAMEOffset(head, track, block, 0);
140 | }
141 |
142 | public static int PhysToMAMEOffset(int head, int track, int block, int sector)
143 | {
144 | int pzone = Array.FindIndex(PZONE_TRACK, x => track < x) - 1;
145 |
146 | int trackRelative = track - PZONE_TRACK[pzone];
147 |
148 | int offsetCalc = MAMEOffsetTable[pzone + (head * 8)];
149 | offsetCalc += BLOCK_SIZE[pzone + head] * 2 * trackRelative;
150 | offsetCalc += block * BLOCK_SIZE[pzone + head];
151 | offsetCalc += sector * SECTOR_SIZE[pzone + head];
152 |
153 | if (offsetCalc >= DISK_SIZE_MAME) throw new ArgumentOutOfRangeException("Offset Result is out of bounds.", "0x" + offsetCalc.ToString("X"));
154 |
155 | return offsetCalc;
156 | }
157 |
158 | public static void LBAToPhys(int lba, byte[] sysData, out int head, out int track, out int block)
159 | {
160 | if (lba < 0 && lba > Leo.MAX_LBA) throw new ArgumentOutOfRangeException("LBA out of range", lba.ToString());
161 |
162 | //Get Disk Type
163 | int diskType = sysData[0x05] & 0x0F;
164 |
165 | //Get Block
166 | if (((lba & 3) == 0) || ((lba & 3) == 3))
167 | block = 0;
168 | else
169 | block = 1;
170 |
171 | //Calculate Head & Track
172 | int VZone = LBAToVZone(lba, diskType);
173 | int PZone = VZoneToPZone(VZone, diskType);
174 |
175 | //Get Head
176 | head = (7 < PZone) ? 1 : 0;
177 |
178 | int calcPZone = PZone - (head * 7);
179 |
180 | int calcTrack = (lba - ((VZone == 0) ? 0 : VZONE_LBA_TBL[diskType, VZone - 1])) / BLOCKS_PER_TRACK;
181 |
182 | //int zoneTrackStart = PZONE_TRACK[calcPZone - head];
183 | int zoneTrackStart = TRACK_START_ZONE_TBL[PZone];
184 | if (head == 1)
185 | {
186 | calcTrack = -calcTrack;
187 | zoneTrackStart = PZONE_TRACK[calcPZone - head];
188 | }
189 | calcTrack += TRACK_START_ZONE_TBL[PZone];
190 |
191 | int calcDefectOffset = (PZone == 0) ? 0 : sysData[8 + PZone - 1];
192 | int calcDefectAmount = sysData[8 + PZone] - calcDefectOffset;
193 |
194 | while ((calcDefectAmount > 0) && ((sysData[0x20 + calcDefectOffset] + zoneTrackStart) <= calcTrack))
195 | {
196 | calcTrack++;
197 | calcDefectOffset++;
198 | calcDefectAmount--;
199 | }
200 |
201 | track = calcTrack;
202 | }
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/mfs_library/Leo/LeoDisk.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.SqlServer.Server;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Security.Cryptography;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using static mfs_library.MFS;
10 | using static System.Net.Mime.MediaTypeNames;
11 |
12 | namespace mfs_library
13 | {
14 | public class LeoDisk
15 | {
16 | public enum DiskFormat
17 | {
18 | SDK,
19 | D64,
20 | RAM,
21 | N64,
22 | MAME,
23 | Invalid
24 | }
25 |
26 | public enum FileSystem
27 | {
28 | MFS,
29 | ATNFS,
30 | Invalid
31 | }
32 |
33 | public string Filename;
34 | public DiskFormat Format;
35 | public FileSystem RAMFileSystem;
36 | public int OffsetToRamArea;
37 | public int OffsetToSysData;
38 | public int DiskType;
39 | public byte[] Data;
40 |
41 | public LeoDisk(string filepath)
42 | {
43 | Load(filepath);
44 | }
45 |
46 | void Load(string filepath)
47 | {
48 | //Assume file is bad first
49 | Format = DiskFormat.Invalid;
50 | RAMFileSystem = FileSystem.Invalid;
51 | OffsetToSysData = -1;
52 | OffsetToRamArea = -1;
53 | if (!File.Exists(filepath))
54 | {
55 | return;
56 | }
57 |
58 | FileStream file = new FileStream(filepath, FileMode.Open);
59 |
60 | if (file.Length > Leo.RamSize[0])
61 | {
62 | //Perform System Area heuristics if the file size is MAME or SDK
63 | bool correctSysData = false;
64 | byte[] sysData = new byte[Leo.SECTOR_SIZE[0]];
65 | if ((file.Length == Leo.DISK_SIZE_MAME) || (file.Length == Leo.DISK_SIZE_SDK))
66 | {
67 | //Check each System Data Block
68 |
69 | //Check Retail SysData
70 | foreach (int lba in Leo.LBA_SYS_PROD)
71 | {
72 | OffsetToSysData = Leo.BLOCK_SIZE[0] * lba;
73 | file.Seek(OffsetToSysData, SeekOrigin.Begin);
74 | file.Read(sysData, 0, sysData.Length);
75 |
76 | bool isEqual = true;
77 | for (int i = 1; i < Leo.SECTORS_PER_BLOCK; i++)
78 | {
79 | byte[] sysDataCompare = new byte[sysData.Length];
80 | file.Read(sysDataCompare, 0, sysDataCompare.Length);
81 |
82 | //Compare Bytes
83 | for (int j = 0; j < sysDataCompare.Length; j++)
84 | {
85 | if (sysDataCompare[j] != sysData[j])
86 | {
87 | isEqual = false;
88 | break;
89 | }
90 | }
91 | //If not equal then don't bother doing more
92 | if (!isEqual) break;
93 | }
94 |
95 | correctSysData = isEqual;
96 |
97 | //If SysData is found then it's fine don't bother checking the rest
98 | if (correctSysData) break;
99 | }
100 |
101 | //Check Dev SysData if not found
102 | if (!correctSysData)
103 | {
104 | sysData = new byte[Leo.SECTOR_SIZE[3]];
105 | foreach (int lba in Leo.LBA_SYS_DEV)
106 | {
107 | OffsetToSysData = Leo.BLOCK_SIZE[0] * lba;
108 | file.Seek(OffsetToSysData, SeekOrigin.Begin);
109 | file.Read(sysData, 0, sysData.Length);
110 |
111 | bool isEqual = true;
112 | for (int i = 1; i < Leo.SECTORS_PER_BLOCK; i++)
113 | {
114 | byte[] sysDataCompare = new byte[sysData.Length];
115 | file.Read(sysDataCompare, 0, sysDataCompare.Length);
116 |
117 | //Compare Bytes
118 | for (int j = 0; j < sysDataCompare.Length; j++)
119 | {
120 | if (sysDataCompare[j] != sysData[j])
121 | {
122 | isEqual = false;
123 | break;
124 | }
125 | }
126 | //If not equal then don't bother doing more
127 | if (!isEqual) break;
128 | }
129 |
130 | correctSysData = isEqual;
131 |
132 | //If SysData is found then it's fine don't bother checking the rest
133 | if (correctSysData) break;
134 | }
135 | }
136 | }
137 |
138 | if (file.Length == Leo.DISK_SIZE_MAME)
139 | {
140 | /* --- Check if it's MAME Format --- */
141 |
142 | //if SysData found
143 | if (correctSysData)
144 | {
145 | DiskType = sysData[0x5] & 0xF;
146 | Format = DiskFormat.MAME;
147 | OffsetToRamArea = 0;
148 | //Data is good.
149 | }
150 | }
151 | else if (file.Length == Leo.DISK_SIZE_SDK)
152 | {
153 | /* --- Check if it's SDK Format --- */
154 |
155 | //if SysData found
156 | if (correctSysData)
157 | {
158 | DiskType = sysData[0x5] & 0xF;
159 | Format = DiskFormat.SDK;
160 | OffsetToRamArea = Leo.LBAToByte(DiskType, 0, Leo.RamStartLBA[DiskType]);
161 | //Data is good.
162 | }
163 | }
164 | else
165 | {
166 | /* --- Check if it's N64 CART Format --- */
167 |
168 | //SHA256 check if N64 Cartridge Port bootloader
169 | byte[] headerTest = new byte[0xFC0];
170 | file.Seek(0x40, SeekOrigin.Begin);
171 | file.Read(headerTest, 0, headerTest.Length);
172 |
173 | SHA256 hashHeader = SHA256.Create();
174 | hashHeader.ComputeHash(headerTest);
175 |
176 | string hashHeaderStr = "";
177 | foreach (byte b in hashHeader.Hash)
178 | hashHeaderStr += b.ToString("x2");
179 |
180 | Console.WriteLine(hashHeaderStr);
181 |
182 | int offsetStart = 0;
183 |
184 | //SHA256 = 53c0088fb777870d0af32f0251e964030e2e8b72e830c26042fd191169508c05
185 | if (hashHeaderStr == "53c0088fb777870d0af32f0251e964030e2e8b72e830c26042fd191169508c05")
186 | {
187 | offsetStart = 0x738C0 - 0x10E8; //Start of User LBA 0 (24 w/ System Area)
188 |
189 | file.Seek(0x1000, SeekOrigin.Begin);
190 | file.Read(sysData, 0, sysData.Length);
191 |
192 | DiskType = sysData[0x5] & 0xF;
193 | Format = DiskFormat.N64;
194 | OffsetToRamArea = Leo.LBAToByte(DiskType, 0, Leo.RamStartLBA[DiskType]) - offsetStart;
195 | OffsetToSysData = 0x1000;
196 | //Data is good.
197 | }
198 | }
199 | }
200 | else
201 | {
202 | /* --- Check if it's RAM Format --- */
203 | if (Array.Exists(Leo.RamSize, x => x == file.Length))
204 | {
205 | DiskType = Array.FindIndex(Leo.RamSize, x => x == file.Length);
206 | Format = DiskFormat.RAM;
207 | OffsetToRamArea = 0;
208 | //Data is good.
209 | }
210 | }
211 |
212 | if (Format != DiskFormat.Invalid)
213 | {
214 | //Copy full file
215 | Data = new byte[file.Length];
216 | file.Seek(0, SeekOrigin.Begin);
217 | file.Read(Data, 0, Data.Length);
218 | //Disk is considered loaded here.
219 | }
220 |
221 | file.Close();
222 |
223 | /* Check RAM FileSystem */
224 | if (Format != DiskFormat.Invalid)
225 | {
226 | //Only check if RAM Area exists (Disk Type 6 has no RAM area)
227 | if (DiskType < 6)
228 | {
229 | //MultiFileSystem
230 | byte[] test = new byte[MFS.RAM_ID.Length];
231 | byte[] firstRAM = ReadLBA(Leo.RamStartLBA[DiskType]);
232 | Array.Copy(firstRAM, test, test.Length);
233 |
234 | //See if equal to RAM_ID, and if so, it is found.
235 | if (Encoding.ASCII.GetString(test).Equals(MFS.RAM_ID))
236 | {
237 | RAMFileSystem = FileSystem.MFS;
238 | }
239 | }
240 | }
241 |
242 | Filename = filepath;
243 | }
244 |
245 | public void Save(string filepath)
246 | {
247 | FileStream file = new FileStream(filepath, FileMode.Create);
248 | file.Write(Data, 0, Data.Length);
249 | file.Close();
250 | }
251 |
252 | public byte[] ReadLBA(int lba)
253 | {
254 | //Do not read anywhere before RAM Area
255 | if (lba < Leo.RamStartLBA[DiskType]) return null;
256 | if (lba > Leo.MAX_LBA) return null;
257 |
258 | //Read Block
259 | byte[] output = new byte[Leo.LBAToByte(DiskType, lba, 1)];
260 | if (Format == DiskFormat.MAME)
261 | {
262 | int sourceOffset = Leo.LBAToMAMEOffset(lba, GetSystemData());
263 | Array.Copy(Data, sourceOffset, output, 0, output.Length);
264 | }
265 | else
266 | {
267 | if (OffsetToRamArea < 0) return null;
268 | int sourceOffset = Leo.LBAToByte(DiskType, Leo.RamStartLBA[DiskType], lba - Leo.RamStartLBA[DiskType]) + OffsetToRamArea;
269 | Array.Copy(Data, sourceOffset, output, 0, output.Length);
270 | }
271 |
272 | return output;
273 | }
274 |
275 | public void WriteLBA(int lba, byte[] data)
276 | {
277 | //Do not write anywhere before RAM Area
278 | if (lba < Leo.RamStartLBA[DiskType]) return;
279 | if (lba > Leo.MAX_LBA) return;
280 |
281 | //Check if data block is exact size of the expected LBA block size
282 | int blockSize = Leo.LBAToByte(DiskType, lba, 1);
283 | if (data.Length != blockSize) return;
284 |
285 | //Write Block
286 | if (Format == DiskFormat.MAME)
287 | {
288 | int destOffset = Leo.LBAToMAMEOffset(lba, GetSystemData());
289 | Array.Copy(data, 0, Data, destOffset, blockSize);
290 | }
291 | else
292 | {
293 | if (OffsetToRamArea < 0) return;
294 | int destOffset = Leo.LBAToByte(DiskType, Leo.RamStartLBA[DiskType], lba - Leo.RamStartLBA[DiskType]) + OffsetToRamArea;
295 | Array.Copy(data, 0, Data, destOffset, blockSize);
296 | }
297 | }
298 |
299 | public byte[] GetSystemData()
300 | {
301 | if (OffsetToSysData < 0) return null;
302 |
303 | byte[] sysData = new byte[Leo.SECTOR_SIZE[0]];
304 |
305 | Array.Copy(Data, OffsetToSysData, sysData, 0, sysData.Length);
306 |
307 | return sysData;
308 | }
309 |
310 | public byte[] GetRAMAreaArray()
311 | {
312 | if (OffsetToRamArea < 0) return null;
313 |
314 | List array = new List();
315 |
316 | for (int lba = Leo.RamStartLBA[DiskType]; lba <= Leo.MAX_LBA; lba++)
317 | {
318 | array.AddRange(ReadLBA(lba));
319 | }
320 |
321 | return array.ToArray();
322 | }
323 | }
324 | }
325 |
--------------------------------------------------------------------------------
/mfs_library/MA/MA2D1.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.Drawing;
7 | using System.Security.Cryptography;
8 | using System.IO;
9 |
10 | namespace mfs_library.MA
11 | {
12 | public static class MA2D1
13 | {
14 | public static Bitmap ConvertToBitmap(byte[] bytes)
15 | {
16 | byte[] headerf = new byte[16];
17 | Array.Copy(bytes, 0x480, headerf, 0, headerf.Length);
18 | string header = Encoding.ASCII.GetString(headerf);
19 |
20 | Bitmap bitmap = null;
21 | if (header.StartsWith("RGBA"))
22 | {
23 | //RAW
24 | int width = Convert.ToInt32(header.Substring(4, 3));
25 | int height = Convert.ToInt32(header.Substring(7, 3));
26 | int size = Convert.ToInt32(header.Substring(10, 6));
27 |
28 | bitmap = new Bitmap(width, height);
29 |
30 | for (int y = 0; y < height; y++)
31 | {
32 | for (int x = 0; x < width; x++)
33 | {
34 | ushort color = (ushort)((bytes[0x490 + (y * width * 2) + (x * 2)] << 8) + bytes[0x490 + (y * width * 2) + (x * 2) + 1]);
35 | bitmap.SetPixel(x, y, RGBA16ToColor(color));
36 | }
37 | }
38 | }
39 | else if (header.StartsWith("NCMP"))
40 | {
41 | //Yay1
42 |
43 | MemoryStream str = new MemoryStream(bytes);
44 | str.Seek(0x490, SeekOrigin.Begin);
45 | byte[] decomp = Yay1.Decompress(str);
46 |
47 | int width = Convert.ToInt32(header.Substring(4, 3));
48 | int height = Convert.ToInt32(header.Substring(7, 3));
49 | int size = Convert.ToInt32(header.Substring(10, 6));
50 |
51 | bitmap = new Bitmap(width, height);
52 |
53 | for (int y = 0; y < height; y++)
54 | {
55 | for (int x = 0; x < width; x++)
56 | {
57 | ushort color = (ushort)((decomp[(y * width * 2) + (x * 2)] << 8) + decomp[(y * width * 2) + (x * 2) + 1]);
58 | bitmap.SetPixel(x, y, RGBA16ToColor(color));
59 | }
60 | }
61 | }
62 |
63 | return bitmap;
64 | }
65 |
66 | public static byte[] ConvertToMA2D1(Bitmap bitmap)
67 | {
68 | byte[] thumbnail = ConvertToRGBA16(bitmap, 24, 24, true);
69 | byte[] image = ConvertToRGBA16(bitmap, 216, 202);
70 | string header = "RGBA216202" + image.Length.ToString("D6");
71 |
72 | List data = new List();
73 | data.AddRange(thumbnail);
74 | data.AddRange(Encoding.ASCII.GetBytes(header));
75 | data.AddRange(image);
76 |
77 | return data.ToArray();
78 | }
79 |
80 | static byte[] ConvertToRGBA16(Bitmap bitmap, int width, int height, bool forcealpha = false)
81 | {
82 | Bitmap output = new Bitmap(width, height);
83 | using (Graphics g = Graphics.FromImage(output))
84 | {
85 | g.DrawImage(bitmap, 0, 0, width, height);
86 | }
87 |
88 | List bytes = new List();
89 | for (int y = 0; y < height; y++)
90 | {
91 | for (int x = 0; x < width; x++)
92 | {
93 | ushort color = ColorToRGBA16(output.GetPixel(x, y), forcealpha);
94 | bytes.Add((byte)(color >> 8));
95 | bytes.Add((byte)(color >> 0));
96 | }
97 | }
98 |
99 | return bytes.ToArray();
100 | }
101 |
102 | static ushort ColorToRGBA16(Color color, bool forcealpha = false)
103 | {
104 | uint r = (uint)((color.R / 255f) * 31f) & 0x1F;
105 | uint g = (uint)((color.G / 255f) * 31f) & 0x1F;
106 | uint b = (uint)((color.B / 255f) * 31f) & 0x1F;
107 | uint a = (uint)((color.A / 255f) * 1f) & 1;
108 | if (forcealpha) a = 1;
109 |
110 | ushort output = (ushort)((r << 11) + (g << 6) + (b << 1) + a);
111 |
112 | return output;
113 | }
114 |
115 | static Color RGBA16ToColor(ushort rgba)
116 | {
117 | int r = (int)((((rgba >> 11) & 0x1F) / 31f) * 255f);
118 | int g = (int)((((rgba >> 6) & 0x1F) / 31f) * 255f);
119 | int b = (int)((((rgba >> 1) & 0x1F) / 31f) * 255f);
120 | int a = (rgba & 1) * 255;
121 |
122 | Color output = Color.FromArgb(a, r, g, b);
123 | return output;
124 | }
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/mfs_library/MA/Yay1.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.Collections;
8 |
9 | namespace mfs_library.MA
10 | {
11 | public static class Yay1
12 | {
13 | public static byte[] Decompress(Stream data)
14 | {
15 | // This is reusing the code from
16 | // https://github.com/Daniel-McCarthy/Mr-Peeps-Compressor/blob/master/PeepsCompress/PeepsCompress/Algorithm%20Classes/YAY0.cs
17 | // By Daniel McCarthy, under the MIT License
18 | int beginningOffset = (int)data.Position;
19 |
20 | byte[] temp = new byte[4];
21 | data.Read(temp, 0, 4);
22 | string header = Encoding.ASCII.GetString(temp).ToLower();
23 |
24 | if (header != "yay0" && header != "yay1")
25 | return null;
26 |
27 | List output = new List();
28 |
29 | data.Read(temp, 0, 4); Array.Reverse(temp, 0, 4);
30 | int outputLength = BitConverter.ToInt32(temp, 0);
31 | data.Read(temp, 0, 4); Array.Reverse(temp, 0, 4);
32 | int compOffset = BitConverter.ToInt32(temp, 0) + beginningOffset;
33 | data.Read(temp, 0, 4); Array.Reverse(temp, 0, 4);
34 | int uncompOffset = BitConverter.ToInt32(temp, 0) + beginningOffset;
35 |
36 | int currentOffset;
37 |
38 | while (output.Count < outputLength)
39 | {
40 | byte bits = (byte)data.ReadByte(); //byte of layout bits
41 | BitArray arrayOfBits = new BitArray(new byte[1] { bits });
42 |
43 | for (int i = 7; i > -1 && (output.Count < outputLength); i--)
44 | {
45 | if (arrayOfBits[i] == true)
46 | {
47 | //non-compressed
48 | //add one byte from uncompressedOffset to newFile
49 |
50 | currentOffset = (int)data.Position;
51 |
52 | data.Seek(uncompOffset, SeekOrigin.Begin);
53 |
54 | output.Add((byte)data.ReadByte());
55 | uncompOffset++;
56 |
57 | data.Seek(currentOffset, SeekOrigin.Begin);
58 |
59 | }
60 | else
61 | {
62 | //compressed
63 | //read 2 bytes
64 | //4 bits = length
65 | //12 bits = offset
66 |
67 | currentOffset = (int)data.Position;
68 | data.Seek(compOffset, SeekOrigin.Begin);
69 |
70 | byte byte1 = (byte)data.ReadByte();
71 | byte byte2 = (byte)data.ReadByte();
72 | compOffset += 2;
73 |
74 | byte byte1Upper = (byte)((byte1 & 0x0F));
75 | byte byte1Lower = (byte)((byte1 & 0xF0) >> 4);
76 |
77 | int finalOffset = ((byte1Upper << 8) | byte2) + 1;
78 | int finalLength;
79 |
80 | if (byte1Lower == 0)
81 | {
82 | data.Seek(uncompOffset, SeekOrigin.Begin);
83 | finalLength = (byte)data.ReadByte() + 0x12;
84 | uncompOffset++;
85 | }
86 | else
87 | {
88 | finalLength = byte1Lower + 2;
89 | }
90 |
91 | for (int j = 0; j < finalLength; j++) //add data for finalLength iterations
92 | {
93 | output.Add(output[output.Count - finalOffset]); //add byte at offset (fileSize - finalOffset) to file
94 | }
95 |
96 | data.Seek(currentOffset, SeekOrigin.Begin); //return to layout bits
97 |
98 | }
99 | }
100 | }
101 |
102 | return output.ToArray();
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/mfs_library/MFS/MFS.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.IO;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace mfs_library
9 | {
10 | public static class MFS
11 | {
12 | //MFS Volume
13 | public struct VolumeAttr
14 | {
15 | public bool isWriteProtected; //Filesystem is Write Protected
16 | public bool isVolumeWriteProtected; //Cannot be written by other applications
17 | public bool isVolumeReadProtected; //Cannot be read by other applications
18 | }
19 |
20 | public const string ROM_ID = "64dd-Multi0201";
21 | public const string RAM_ID = "64dd-Multi0101";
22 |
23 | //MFS FAT
24 | public enum FAT : ushort
25 | {
26 | Unused = 0x0000,
27 | DontManage = 0xFFFD,
28 | Prohibited = 0xFFFE,
29 | LastFileBlock = 0xFFFF
30 | }
31 |
32 | public const int FAT_MAX = 2874;
33 |
34 | //MFS Entry
35 | public struct EntryAttr
36 | {
37 | public bool CopyLimit; //Limit Copy
38 | public bool Encode; //Encode
39 | public bool Hidden; //Hidden
40 | public bool DisableRead; //Cannot be read by other applications
41 | public bool DisableWrite; //Cannot be written, renamed, or deleted by other applications
42 | }
43 |
44 | public static readonly ushort[] EntryLimit = { 899, 814, 729, 644, 559, 474, 0 };
45 |
46 | public class Date
47 | {
48 | public uint Year;
49 | public uint Month;
50 | public uint Day;
51 | public uint Hour;
52 | public uint Minute;
53 | public uint Second;
54 |
55 | public Date()
56 | {
57 | Year = (uint)DateTime.Now.Year;
58 | Month = (uint)DateTime.Now.Month;
59 | Day = (uint)DateTime.Now.Day;
60 | Hour = (uint)DateTime.Now.Hour;
61 | Minute = (uint)DateTime.Now.Minute;
62 | Second = (uint)DateTime.Now.Second;
63 | }
64 |
65 | public Date(uint data)
66 | {
67 | Load(data);
68 | }
69 |
70 | public void Load(uint data)
71 | {
72 | Year = (data >> 25) + 1996;
73 | Month = (data >> 21) & 0xF;
74 | Day = (data >> 16) & 0x1F;
75 | Hour = (data >> 11) & 0x1F;
76 | Minute = (data >> 5) & 0x3F;
77 | Second = ((data >> 0) & 0x1F) * 2;
78 | }
79 |
80 | public uint Save()
81 | {
82 | uint temp = 0;
83 |
84 | temp |= (Year - 1996) << 25;
85 | temp |= Month << 21;
86 | temp |= Day << 16;
87 | temp |= Hour << 11;
88 | temp |= Minute << 5;
89 | temp |= (Second / 2) << 0;
90 |
91 | return temp;
92 | }
93 | }
94 |
95 | enum Error
96 | {
97 | Good = 0, Argument, Filename, FileNotExist, DiskFull, FileAlreadyExists
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/mfs_library/MFS/MFSDef.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.IO;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace mfs_library
9 | {
10 | public class MFSRAMVolume
11 | {
12 | public MFS.VolumeAttr Attributes;
13 | public byte DiskType;
14 | public string Name;
15 | public MFS.Date Date;
16 | public ushort Renewal;
17 | public byte Country;
18 |
19 | public ushort[] FAT; //5748 / 2 = 2874 FAT entries
20 | public List Entries;
21 |
22 | public MFSRAMVolume(byte[] Data, int Offset)
23 | {
24 | Load(Data, Offset);
25 | }
26 |
27 | public void Load(byte[] Data, int Offset)
28 | {
29 | Attributes.isWriteProtected = (Data[Offset + 0x0E] & 0x80) != 0;
30 | Attributes.isVolumeReadProtected = (Data[Offset + 0x0E] & 0x40) != 0;
31 | Attributes.isVolumeWriteProtected = (Data[Offset + 0x0E] & 0x20) != 0;
32 | DiskType = Data[Offset + 0x0F];
33 | Name = Util.ReadStringN(Data, Offset + 0x10, 0x14);
34 | Date = new MFS.Date(Util.ReadBEU32(Data, Offset + 0x24));
35 | Renewal = Util.ReadBEU16(Data, Offset + 0x28);
36 | Country = Data[Offset + 0x2A];
37 |
38 | //Get All FAT Entries
39 | FAT = new ushort[MFS.FAT_MAX];
40 | for (int i = 0; i < MFS.FAT_MAX; i++)
41 | {
42 | FAT[i] = Util.ReadBEU16(Data, Offset + 0x3C + (i * 2));
43 | }
44 |
45 | //Get All File Entries
46 | Entries = new List();
47 | for (int i = 0; i < MFS.EntryLimit[DiskType]; i++)
48 | {
49 | int check = (Data[Offset + 0x16B0 + (i * 0x30)] & 0xC0);
50 | if (check == 0x80)
51 | {
52 | //Directory
53 | MFSDirectory dir = new MFSDirectory(Data, Offset + 0x16B0 + (i * 0x30));
54 | Entries.Add(dir);
55 | }
56 | else if (check == 0x40)
57 | {
58 | //File
59 | MFSFile file = new MFSFile(Data, Offset + 0x16B0 + (i * 0x30));
60 | Entries.Add(file);
61 | }
62 | }
63 | }
64 |
65 | public byte[] SaveToArray()
66 | {
67 | byte[] temp = new byte[Leo.LBAToByte(DiskType, Leo.RamStartLBA[DiskType], 3)];
68 |
69 | Util.WriteStringN(MFS.RAM_ID, temp, 0, MFS.RAM_ID.Length);
70 | temp[0x0E] = (byte)(0 | (Attributes.isVolumeWriteProtected ? 0x20 : 0) | (Attributes.isVolumeReadProtected ? 0x40 : 0) | (Attributes.isWriteProtected ? 0x80 : 0));
71 | temp[0x0F] = (byte)DiskType;
72 |
73 | Util.WriteStringN(Name, temp, 0x10, 0x14);
74 | Util.WriteBEU32(Date.Save(), temp, 0x24);
75 | Util.WriteBEU16(Renewal, temp, 0x28);
76 | temp[0x2A] = Country;
77 |
78 | //Save FAT Entries
79 | for (int i = 0; i < FAT.Length; i++)
80 | {
81 | Util.WriteBEU16(FAT[i], temp, 0x3C + (i * 2));
82 | }
83 |
84 | //Save File Entries 0x16B0
85 | for (int i = 0; i < Entries.Count; i++)
86 | {
87 | byte[] tempentry;
88 | if (Entries[i].GetType() == typeof(MFSDirectory))
89 | tempentry = ((MFSDirectory)Entries[i]).Save();
90 | else
91 | tempentry = ((MFSFile)Entries[i]).Save();
92 | Array.Copy(tempentry, 0, temp, 0x16B0 + (0x30 * i), 0x30);
93 | }
94 |
95 | //Checksum
96 | uint crc = 0;
97 | for (int i = 0; i < (temp.Length / 4); i++)
98 | {
99 | crc ^= Util.ReadBEU32(temp, i * 4);
100 | }
101 | Util.WriteBEU32(crc, temp, 0x2C);
102 |
103 | return temp;
104 | }
105 | }
106 |
107 | public class MFSEntry
108 | {
109 | public MFS.EntryAttr Attributes;
110 | public ushort ParentDirectory;
111 | public string CompanyCode;
112 | public string GameCode;
113 |
114 | public string Name;
115 |
116 | public byte Renewal;
117 | public MFS.Date Date;
118 |
119 | public MFSEntry(string _name, string _ccode, string _gcode, ushort _dir = 0)
120 | {
121 | Attributes.CopyLimit = false;
122 | Attributes.Encode = false;
123 | Attributes.Hidden = false;
124 | Attributes.DisableRead = false;
125 | Attributes.DisableWrite = false;
126 | Name = _name;
127 | CompanyCode = _ccode;
128 | GameCode = _gcode;
129 | ParentDirectory = _dir;
130 | Renewal = 0;
131 | Date = new MFS.Date();
132 | }
133 |
134 | public MFSEntry(byte[] Data, int Offset)
135 | {
136 | LoadEntry(Data, Offset);
137 | }
138 |
139 | public void LoadEntry(byte[] Data, int Offset)
140 | {
141 | Attributes.CopyLimit = (Util.ReadBEU16(Data, Offset) & 0x0200) != 0;
142 | Attributes.Encode = (Util.ReadBEU16(Data, Offset) & 0x0400) != 0;
143 | Attributes.Hidden = (Util.ReadBEU16(Data, Offset) & 0x0800) != 0;
144 | Attributes.DisableRead = (Util.ReadBEU16(Data, Offset) & 0x1000) != 0;
145 | Attributes.DisableWrite = (Util.ReadBEU16(Data, Offset) & 0x2000) != 0;
146 |
147 | ParentDirectory = Util.ReadBEU16(Data, Offset + 0x02);
148 | CompanyCode = Util.ReadStringN(Data, Offset + 0x04, 2);
149 | GameCode = Util.ReadStringN(Data, Offset + 0x06, 4);
150 |
151 | Name = Util.ReadStringN(Data, Offset + 0x10, 0x14);
152 |
153 | Renewal = Data[Offset + 0x2A];
154 | Date = new MFS.Date(Util.ReadBEU32(Data, Offset + 0x2C));
155 | }
156 |
157 | public byte[] SaveEntry()
158 | {
159 | byte[] temp = new byte[0x30];
160 |
161 | //Attributes
162 | temp[0] = (byte)(0 | (Attributes.CopyLimit ? 0x02 : 0) | (Attributes.Encode ? 0x04 : 0) | (Attributes.Hidden ? 0x08 : 0)
163 | | (Attributes.DisableRead ? 0x10 : 0) | (Attributes.DisableWrite ? 0x20 : 0));
164 |
165 | Util.WriteBEU16(ParentDirectory, temp, 2);
166 | Util.WriteStringN(CompanyCode, temp, 4, 2);
167 | Util.WriteStringN(GameCode, temp, 6, 4);
168 | Util.WriteStringN(Name, temp, 0x10, 0x14);
169 |
170 | temp[0x2A] = Renewal;
171 | Util.WriteBEU32(Date.Save(), temp, 0x2C);
172 |
173 | return temp;
174 | }
175 |
176 | public virtual string GetEntryName()
177 | {
178 | return Name;
179 | }
180 | }
181 |
182 | public class MFSDirectory : MFSEntry
183 | {
184 | public ushort DirectoryID;
185 |
186 | public MFSDirectory(byte[] Data, int Offset) : base(Data, Offset)
187 | {
188 | Load(Data, Offset);
189 | }
190 |
191 | public void Load(byte[] Data, int Offset)
192 | {
193 | DirectoryID = Util.ReadBEU16(Data, Offset + 0x0A);
194 | }
195 |
196 | public byte[] Save()
197 | {
198 | byte[] temp = SaveEntry();
199 |
200 | Util.WriteBEU16(DirectoryID, temp, 0x0A);
201 | temp[0] |= 0x80;
202 |
203 | return temp;
204 | }
205 | }
206 |
207 | public class MFSFile : MFSEntry
208 | {
209 | public ushort FATEntry;
210 | public uint Size;
211 |
212 | public string Ext;
213 | public byte CopyNb;
214 |
215 | public MFSFile(string _name, string _ccode, string _gcode, string _ext, uint _size, ushort _dir = 0) : base(_name, _ccode, _gcode, _dir)
216 | {
217 | Ext = _ext;
218 | Size = _size;
219 | FATEntry = 0xFFFF;
220 | CopyNb = 0;
221 | }
222 |
223 | public MFSFile(byte[] Data, int Offset) : base(Data, Offset)
224 | {
225 | Load(Data, Offset);
226 | }
227 |
228 | public void Load(byte[] Data, int Offset)
229 | {
230 | FATEntry = Util.ReadBEU16(Data, Offset + 0x0A);
231 | Size = Util.ReadBEU32(Data, Offset + 0x0C);
232 |
233 | Ext = Util.ReadStringN(Data, Offset + 0x24, 5);
234 | CopyNb = Data[Offset + 0x29];
235 | }
236 |
237 | public byte[] Save()
238 | {
239 | byte[] temp = SaveEntry();
240 |
241 | Util.WriteBEU16(FATEntry, temp, 0x0A);
242 | Util.WriteBEU32(Size, temp, 0x0C);
243 |
244 | Util.WriteStringN(Ext, temp, 0x24, 5);
245 | temp[0x29] = CopyNb;
246 | temp[0] |= 0x40;
247 | return temp;
248 | }
249 |
250 | public override string GetEntryName()
251 | {
252 | return Name + "." + Ext;
253 | }
254 | }
255 | }
256 |
--------------------------------------------------------------------------------
/mfs_library/MFS/MFSDisk.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.IO;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Security.Cryptography;
8 | using System.Runtime.CompilerServices;
9 | using static mfs_library.MFS;
10 |
11 | namespace mfs_library
12 | {
13 | public class MFSDisk
14 | {
15 | public LeoDisk Disk;
16 | public MFSRAMVolume RAMVolume;
17 |
18 | public MFSDisk(string filepath)
19 | {
20 | //Load Disk
21 | Disk = new LeoDisk(filepath);
22 | LoadRAMVolume();
23 | }
24 |
25 | public MFSDisk(LeoDisk disk)
26 | {
27 | //Reuse already loaded disk
28 | Disk = disk;
29 | LoadRAMVolume();
30 | }
31 |
32 | void LoadRAMVolume()
33 | {
34 | //Load RAM Volume
35 | if (Disk.Format == LeoDisk.DiskFormat.Invalid)
36 | return;
37 | if (Disk.RAMFileSystem != LeoDisk.FileSystem.MFS)
38 | return;
39 |
40 | RAMVolume = new MFSRAMVolume(Disk.GetRAMAreaArray(), 0);
41 | }
42 |
43 | public void Save(string filepath)
44 | {
45 | //Save RAM Volume FAT Table into Disk data
46 | byte[] volume = RAMVolume.SaveToArray();
47 | int offset = 0;
48 | for (int i = 0; i < 3; i++)
49 | {
50 | byte[] temp = new byte[Leo.LBAToByte(Disk.DiskType, Leo.RamStartLBA[Disk.DiskType] + i, 1)];
51 | Array.Copy(volume, offset, temp, 0, temp.Length);
52 | Disk.WriteLBA(Leo.RamStartLBA[Disk.DiskType] + i, temp);
53 | offset += temp.Length;
54 | }
55 |
56 | offset = 0;
57 | for (int i = 3; i < 6; i++)
58 | {
59 | byte[] temp = new byte[Leo.LBAToByte(Disk.DiskType, Leo.RamStartLBA[Disk.DiskType] + i, 1)];
60 | Array.Copy(volume, offset, temp, 0, temp.Length);
61 | Disk.WriteLBA(Leo.RamStartLBA[Disk.DiskType] + i, temp);
62 | offset += temp.Length;
63 | }
64 |
65 | //Save the Disk data
66 | Disk.Save(filepath);
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/mfs_library/MFS/MFSUtil_Directory.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 mfs_library
8 | {
9 | public static partial class MFSRAMUtil
10 | {
11 | public static MFSDirectory GetDirectoryFromPath(MFSDisk mfsDisk, string dirpath)
12 | {
13 | string[] path = dirpath.Split('/');
14 | path[0] = "/";
15 |
16 | return GetDirectoryFromList(mfsDisk, path.Take(path.Length - 1).ToArray(), GetAllDirectoriesFromDirID(mfsDisk, 0xFFFE));
17 | }
18 |
19 | private static MFSDirectory GetDirectoryFromList(MFSDisk mfsDisk, string[] names, MFSDirectory[] list)
20 | {
21 | foreach (MFSDirectory dir in list)
22 | {
23 | if (dir.Name == names[0])
24 | {
25 | if (names.Length > 1)
26 | return GetDirectoryFromList(mfsDisk, names.Skip(1).ToArray(), GetAllDirectoriesFromDirID(mfsDisk, dir.DirectoryID));
27 | else
28 | return dir;
29 | }
30 | }
31 | return null;
32 | }
33 |
34 | public static MFSDirectory[] GetAllDirectoriesFromDirID(MFSDisk mfsDisk, ushort id)
35 | {
36 | List list = new List();
37 |
38 | foreach (MFSEntry entry in mfsDisk.RAMVolume.Entries)
39 | {
40 | if (entry.GetType() == typeof(MFSDirectory) && ((MFSDirectory)entry).ParentDirectory == id)
41 | {
42 | list.Add((MFSDirectory)entry);
43 | }
44 | }
45 |
46 | return list.ToArray();
47 | }
48 |
49 | public static MFSDirectory GetDirectoryFromID(MFSDisk mfsDisk, ushort id)
50 | {
51 | foreach (MFSEntry entry in mfsDisk.RAMVolume.Entries)
52 | {
53 | if (entry.GetType() == typeof(MFSDirectory) && ((MFSDirectory)entry).DirectoryID == id)
54 | {
55 | return (MFSDirectory)entry;
56 | }
57 | }
58 | return null;
59 | }
60 |
61 | // As there can be multiple directories with the same name, it is preferable to input a parent Directory ID.
62 | public static bool CheckIfDirectoryAlreadyExists(MFSDisk mfsDisk, string _name, ushort _dir = 0xFFFF)
63 | {
64 | foreach (MFSDirectory entry in GetAllDirectoriesFromDirID(mfsDisk, _dir))
65 | {
66 | if (entry.Name.Equals(_name))
67 | {
68 | return true;
69 | }
70 | }
71 | return false;
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/mfs_library/MFS/MFSUtil_File.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.IO;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace mfs_library
9 | {
10 | public static partial class MFSRAMUtil
11 | {
12 | // Additional Methods
13 | public static byte[] ReadFile(MFSDisk mfsDisk, string filepath)
14 | {
15 | MFSFile file = GetFileFromPath(mfsDisk, filepath);
16 | if (file != null)
17 | return ReadFile(mfsDisk, file);
18 | else
19 | return null;
20 | }
21 |
22 | public static byte[] ReadFile(MFSDisk mfsDisk, MFSFile file)
23 | {
24 | byte[] filedata = new byte[file.Size];
25 |
26 | //Add FAT Entries and Copy to data to blocks
27 | ushort nextblock = file.FATEntry;
28 | uint offset = 0;
29 | uint size = file.Size;
30 |
31 | //Recursively copy blocks
32 | do
33 | {
34 | byte[] blockdata = mfsDisk.Disk.ReadLBA(Leo.RamStartLBA[mfsDisk.RAMVolume.DiskType] + nextblock);
35 | int blocksize = blockdata.Length;
36 | Array.Copy(blockdata, 0, filedata, offset, Math.Min(blocksize, size));
37 | offset += (uint)Math.Min(blocksize, size);
38 | size -= (uint)Math.Min(blocksize, size);
39 |
40 | nextblock = mfsDisk.RAMVolume.FAT[nextblock];
41 | }
42 | while (nextblock != (ushort)MFS.FAT.LastFileBlock);
43 |
44 | return filedata;
45 | }
46 |
47 | public static bool WriteFile(MFSDisk mfsDisk, byte[] filedata, string filepath)
48 | {
49 | MFSDirectory _dir = GetDirectoryFromPath(mfsDisk, filepath);
50 |
51 | return WriteFile(mfsDisk, filedata, Path.GetFileName(filepath), _dir.DirectoryID);
52 | }
53 |
54 | public static bool WriteFile(MFSDisk mfsDisk, byte[] filedata, string name, ushort dir = 0)
55 | {
56 | string _name = Path.GetFileNameWithoutExtension(name);
57 | string _ext = Path.GetExtension(name);
58 |
59 | if (_ext.StartsWith("."))
60 | _ext = _ext.Substring(1);
61 |
62 | MFSFile file = new MFSFile(_name, mfsDisk.RAMVolume.Entries[0].CompanyCode, mfsDisk.RAMVolume.Entries[0].GameCode, _ext, (uint)filedata.Length, dir);
63 | return WriteFile(mfsDisk, filedata, file);
64 | }
65 |
66 | public static bool WriteFile(MFSDisk mfsDisk, byte[] filedata, MFSFile file)
67 | {
68 | if (CheckIfFileAlreadyExists(mfsDisk, file.Name, file.Ext, file.ParentDirectory))
69 | return false;
70 | if (GetFreeSpaceSize(mfsDisk) < filedata.Length)
71 | return false;
72 |
73 | int FATentry = -1;
74 | int lastFATentry = -1;
75 | int offset = 0;
76 |
77 | //Write free data on every free block from the start
78 | for (int i = 6; i < Leo.SIZE_LBA - Leo.RamStartLBA[mfsDisk.RAMVolume.DiskType]; i++)
79 | {
80 | if (mfsDisk.RAMVolume.FAT[i] == (ushort)MFS.FAT.Unused)
81 | {
82 | if (FATentry == -1)
83 | {
84 | FATentry = i;
85 | file.FATEntry = (ushort)i;
86 | }
87 |
88 | //Write File Data
89 | byte[] blockdata = new byte[Leo.LBAToByte(mfsDisk.RAMVolume.DiskType, Leo.RamStartLBA[mfsDisk.RAMVolume.DiskType] + i, 1)];
90 | Array.Copy(filedata, offset, blockdata, 0, Math.Min(blockdata.Length, filedata.Length - offset));
91 | mfsDisk.Disk.WriteLBA(Leo.RamStartLBA[mfsDisk.RAMVolume.DiskType] + i, blockdata);
92 |
93 | offset += Math.Min(blockdata.Length, filedata.Length - offset);
94 |
95 | //Change FAT entry
96 | if (lastFATentry != -1)
97 | {
98 | mfsDisk.RAMVolume.FAT[lastFATentry] = (ushort)i;
99 | }
100 | if (offset == filedata.Length)
101 | {
102 | mfsDisk.RAMVolume.FAT[i] = (ushort)MFS.FAT.LastFileBlock;
103 |
104 | mfsDisk.RAMVolume.Entries.Add(file);
105 | return true;
106 | }
107 | lastFATentry = i;
108 | }
109 | }
110 | return false;
111 | }
112 |
113 | public static bool DeleteFile(MFSDisk mfsDisk, string filepath)
114 | {
115 | MFSFile file = GetFileFromPath(mfsDisk, filepath);
116 | if (file != null)
117 | return DeleteFile(mfsDisk, file);
118 | else
119 | return false;
120 | }
121 |
122 | public static bool DeleteFile(MFSDisk mfsDisk, MFSFile file)
123 | {
124 | //Delete FAT Entries recursively
125 | ushort nextblock = file.FATEntry;
126 | ushort lastblock = 0;
127 | do
128 | {
129 | lastblock = nextblock;
130 | nextblock = mfsDisk.RAMVolume.FAT[nextblock];
131 | mfsDisk.RAMVolume.FAT[lastblock] = 0;
132 | }
133 | while (nextblock != (ushort)MFS.FAT.LastFileBlock);
134 |
135 | //Delete File Data
136 | if (mfsDisk.RAMVolume.Entries.Remove(file))
137 | {
138 | Console.WriteLine("found");
139 | }
140 |
141 | return true;
142 | }
143 |
144 | public static bool MoveFile(MFSDisk mfsDisk, string filepathin, string filepathout)
145 | {
146 | MFSFile file = GetFileFromPath(mfsDisk, filepathin);
147 | if (file != null)
148 | {
149 | if (filepathout.StartsWith("/"))
150 | {
151 | MFSDirectory dir = GetDirectoryFromPath(mfsDisk, filepathout);
152 | if (dir != null)
153 | file.ParentDirectory = dir.DirectoryID;
154 | else
155 | return false;
156 | }
157 | if (!filepathout.EndsWith("/"))
158 | {
159 | file.Name = Path.GetFileNameWithoutExtension(filepathout);
160 | string newext = Path.GetExtension(filepathout);
161 | if (newext != "")
162 | newext = newext.Substring(1);
163 | file.Ext = newext;
164 | }
165 | return true;
166 | }
167 | else
168 | return false;
169 | }
170 |
171 | //Utilities
172 | public static MFSFile GetFileFromPath(MFSDisk mfsDisk, string filepath)
173 | {
174 | MFSDirectory dir = GetDirectoryFromPath(mfsDisk, filepath);
175 | string[] path = filepath.Split('/');
176 | path[0] = "/";
177 |
178 | string filename = Path.GetFileNameWithoutExtension(filepath);
179 | string ext = Path.GetExtension(filepath);
180 | if (ext.StartsWith("."))
181 | ext = ext.Substring(1);
182 |
183 | foreach (MFSFile file in GetAllFilesFromDirID(mfsDisk, dir.DirectoryID))
184 | {
185 | if (file.Name.Equals(filename) && file.Ext.Equals(ext))
186 | {
187 | return file;
188 | }
189 | }
190 |
191 | return null;
192 | }
193 |
194 | public static MFSFile[] GetAllFilesFromDirID(MFSDisk mfsDisk, ushort id)
195 | {
196 | List list = new List();
197 |
198 | foreach (MFSEntry entry in mfsDisk.RAMVolume.Entries)
199 | {
200 | if (entry.GetType() == typeof(MFSFile))
201 | {
202 | if (id == 0xFFFF || ((MFSFile)entry).ParentDirectory == id)
203 | list.Add((MFSFile)entry);
204 | }
205 | }
206 |
207 | return list.ToArray();
208 | }
209 |
210 | public static string GetFullPath(MFSDisk mfsDisk, MFSEntry file)
211 | {
212 | string temp = GetParentDirectoryPath(mfsDisk, file) + file.Name;
213 |
214 | if (file.GetType() == typeof(MFSFile) && ((MFSFile)file).Ext != "")
215 | temp += "." + ((MFSFile)file).Ext;
216 | else if (file.GetType() == typeof(MFSDirectory))
217 | temp += "/";
218 |
219 | return temp;
220 | }
221 |
222 | public static string GetParentDirectoryPath(MFSDisk mfsDisk, MFSEntry file)
223 | {
224 | string temp = "";
225 | ushort dir_id = 0;
226 | MFSDirectory dir = GetDirectoryFromID(mfsDisk, file.ParentDirectory);
227 | while (dir != null)
228 | {
229 | dir_id = dir.ParentDirectory;
230 | temp = dir.Name + (dir_id != 0xFFFE ? "/" : "") + temp;
231 | dir = GetDirectoryFromID(mfsDisk, dir_id);
232 | }
233 |
234 | return temp;
235 | }
236 |
237 | // As there can be multiple files with the same name, it is preferable to input a parent Directory ID.
238 | public static bool CheckIfFileAlreadyExists(MFSDisk mfsDisk, string _filename, ushort _dir = 0xFFFF)
239 | {
240 | string _name = Path.GetFileNameWithoutExtension(_filename);
241 | string _ext = Path.GetExtension(_filename);
242 |
243 | if (_ext.StartsWith("."))
244 | _ext = _ext.Substring(1);
245 |
246 | return CheckIfFileAlreadyExists(mfsDisk, _name, _ext, _dir);
247 | }
248 |
249 | public static bool CheckIfFileAlreadyExists(MFSDisk mfsDisk, string _name, string _ext, ushort _dir = 0xFFFF)
250 | {
251 | foreach (MFSFile file in GetAllFilesFromDirID(mfsDisk, _dir))
252 | {
253 | if (file.Name.Equals(_name) && file.Ext.Equals(_ext))
254 | {
255 | return true;
256 | }
257 | }
258 | return false;
259 | }
260 | }
261 | }
262 |
--------------------------------------------------------------------------------
/mfs_library/MFS/MFSUtil_Other.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 mfs_library
8 | {
9 | public static partial class MFSRAMUtil
10 | {
11 | public static int GetTotalUsedSize(MFSDisk mfsDisk)
12 | {
13 | int totalsize = 0;
14 | for (int i = 6; i < Leo.SIZE_LBA - Leo.RamStartLBA[mfsDisk.RAMVolume.DiskType]; i++)
15 | {
16 | switch (mfsDisk.RAMVolume.FAT[i])
17 | {
18 | case (ushort)MFS.FAT.Unused:
19 | case (ushort)MFS.FAT.Prohibited:
20 | case (ushort)MFS.FAT.DontManage:
21 | break;
22 | default:
23 | totalsize += Leo.LBAToByte(mfsDisk.RAMVolume.DiskType, Leo.RamStartLBA[mfsDisk.RAMVolume.DiskType] + i, 1);
24 | break;
25 | }
26 | }
27 | return totalsize;
28 | }
29 |
30 | public static int GetFreeSpaceSize(MFSDisk mfsDisk)
31 | {
32 | int unused = Leo.RamSize[mfsDisk.RAMVolume.DiskType] - GetTotalUsedSize(mfsDisk) - Leo.LBAToByte(mfsDisk.RAMVolume.DiskType, Leo.RamStartLBA[mfsDisk.RAMVolume.DiskType], 6);
33 |
34 | return unused;
35 | }
36 |
37 | public static int GetCapacitySize(MFSDisk mfsDisk)
38 | {
39 | int totalsize = 0;
40 | for (int i = 6; i < Leo.SIZE_LBA - Leo.RamStartLBA[mfsDisk.RAMVolume.DiskType]; i++)
41 | {
42 | switch (mfsDisk.RAMVolume.FAT[i])
43 | {
44 | case (ushort)MFS.FAT.Prohibited:
45 | case (ushort)MFS.FAT.DontManage:
46 | break;
47 | default:
48 | totalsize += Leo.LBAToByte(mfsDisk.RAMVolume.DiskType, Leo.RamStartLBA[mfsDisk.RAMVolume.DiskType] + i, 1);
49 | break;
50 | }
51 | }
52 | return totalsize;
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/mfs_library/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // Les informations générales relatives à un assembly dépendent de
6 | // l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations
7 | // associées à un assembly.
8 | [assembly: AssemblyTitle("mfs_library")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("mfs_library")]
13 | [assembly: AssemblyCopyright("Copyright © LuigiBlood 2022")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly
18 | // aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de
19 | // COM, affectez la valeur true à l'attribut ComVisible sur ce type.
20 | [assembly: ComVisible(false)]
21 |
22 | // Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM
23 | [assembly: Guid("8d1cf3e5-ba0f-4790-ba0a-c52b79302da3")]
24 |
25 | // Les informations de version pour un assembly se composent des quatre valeurs suivantes :
26 | //
27 | // Version principale
28 | // Version secondaire
29 | // Numéro de build
30 | // Révision
31 | //
32 | // Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut
33 | // en utilisant '*', comme indiqué ci-dessous :
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.2.0.0")]
36 | [assembly: AssemblyFileVersion("1.2.0.0")]
37 |
--------------------------------------------------------------------------------
/mfs_library/Util/SJISUtil.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace mfs_library
9 | {
10 | public static class SJISUtil
11 | {
12 | static Dictionary leoMapping = new Dictionary();
13 | static bool isMappingReady = false;
14 |
15 | static void PrepareMapping()
16 | {
17 | if (isMappingReady)
18 | return;
19 |
20 | leoMapping = new Dictionary();
21 | leoMapping.Add(0x86A3, '\u2660'); //Spade
22 | leoMapping.Add(0x86A4, '\u2663'); //Club
23 | leoMapping.Add(0x86A5, '\u2665'); //Heart
24 | leoMapping.Add(0x86A6, '\u2666'); //Diamond
25 |
26 | isMappingReady = true;
27 | }
28 |
29 | public static byte[] EncodeStringToSJIS(string str)
30 | {
31 | PrepareMapping();
32 |
33 | Encoding encode = Encoding.GetEncoding(932, new EncoderExceptionFallback(), new CustomDecoder());
34 | List output = new List();
35 |
36 | foreach (char c in str)
37 | {
38 | byte[] byt = { };
39 |
40 | try
41 | {
42 | byt = encode.GetBytes(c.ToString());
43 | }
44 | catch (EncoderFallbackException e)
45 | {
46 | //Any invalid chars will dealt with here
47 | ushort[] keys = leoMapping.Keys.ToArray(); //SJIS
48 | char[] values = leoMapping.Values.ToArray(); //Unicode
49 |
50 | Debug.Assert(keys.Length == values.Length);
51 |
52 | //Reverse Search
53 | for (int i = 0; i < keys.Length; i++)
54 | {
55 | if (values[i] == e.CharUnknown)
56 | {
57 | byt = BitConverter.GetBytes(keys[i]).Reverse().ToArray();
58 | break;
59 | }
60 | }
61 | }
62 |
63 | foreach (byte b in byt)
64 | output.Add(b);
65 | }
66 |
67 | return output.ToArray();
68 | }
69 |
70 | //Decoder
71 | public class CustomDecoder : DecoderFallback
72 | {
73 | public string DefaultString;
74 | internal Dictionary mapping;
75 |
76 | public CustomDecoder() : this("*")
77 | {
78 | }
79 |
80 | public CustomDecoder(string defaultString)
81 | {
82 | this.DefaultString = defaultString;
83 |
84 | // Create table of mappings
85 | PrepareMapping();
86 | mapping = leoMapping;
87 | }
88 |
89 | public override DecoderFallbackBuffer CreateFallbackBuffer()
90 | {
91 | return new CustomDecoderFallbackBuffer(this);
92 | }
93 |
94 | public override int MaxCharCount
95 | {
96 | get { return 2; }
97 | }
98 | }
99 |
100 | public class CustomDecoderFallbackBuffer : DecoderFallbackBuffer
101 | {
102 | int count = -1; // Number of characters to return
103 | int index = -1; // Index of character to return
104 | CustomDecoder fb;
105 | string charsToReturn;
106 |
107 | public CustomDecoderFallbackBuffer(CustomDecoder fallback)
108 | {
109 | this.fb = fallback;
110 | }
111 |
112 | public override bool Fallback(byte[] bytesUnknown, int index)
113 | {
114 | // Return false if there are already characters to map.
115 | if (count >= 1) return false;
116 |
117 | // Determine number of characters to return.
118 | charsToReturn = String.Empty;
119 |
120 | if (bytesUnknown.Length == 2)
121 | {
122 | ushort key = (ushort)((bytesUnknown[0] << 8) + bytesUnknown[1]);
123 | if (fb.mapping.ContainsKey(key))
124 | {
125 | charsToReturn = Convert.ToString(fb.mapping[key]);
126 | count = 1;
127 | }
128 | else
129 | {
130 | // Return default.
131 | charsToReturn = fb.DefaultString;
132 | count = 1;
133 | }
134 | this.index = charsToReturn.Length - 1;
135 | }
136 | else
137 | {
138 | //Only full width
139 | charsToReturn = fb.DefaultString;
140 | count = 1;
141 | }
142 | return true;
143 | }
144 |
145 | public override char GetNextChar()
146 | {
147 | // We'll return a character if possible, so subtract from the count of chars to return.
148 | count--;
149 | // If count is less than zero, we've returned all characters.
150 | if (count < 0)
151 | return '\u0000';
152 |
153 | this.index--;
154 | return charsToReturn[this.index + 1];
155 | }
156 |
157 | public override bool MovePrevious()
158 | {
159 | // Original: if count >= -1 and pos >= 0
160 | if (count >= -1)
161 | {
162 | count++;
163 | return true;
164 | }
165 | else
166 | {
167 | return false;
168 | }
169 | }
170 |
171 | public override int Remaining
172 | {
173 | get { return count < 0 ? 0 : count; }
174 | }
175 |
176 | public override void Reset()
177 | {
178 | count = -1;
179 | index = -1;
180 | }
181 | }
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/mfs_library/Util/Util.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 mfs_library
8 | {
9 | public static class Util
10 | {
11 | //Read Methods
12 | public static uint ReadBEU32(byte[] Data, int Offset)
13 | {
14 | return (uint)((Data[Offset + 0] << 24) | (Data[Offset + 1] << 16) | (Data[Offset + 2] << 8) | (Data[Offset + 3] << 0));
15 | }
16 |
17 | public static ushort ReadBEU16(byte[] Data, int Offset)
18 | {
19 | return (ushort)((Data[Offset + 0] << 8) | (Data[Offset + 1] << 0));
20 | }
21 |
22 | public static string ReadStringN(byte[] Data, int Offset, int Size)
23 | {
24 | return Encoding.GetEncoding(932, new EncoderReplacementFallback(), new SJISUtil.CustomDecoder()).GetString(Data, Offset, Size).TrimEnd('\x00');
25 | }
26 |
27 | //Write Methods
28 | public static void WriteBEU32(uint Input, byte[] Data, int Offset)
29 | {
30 | Data[Offset + 0] = (byte)((Input >> 24) & 0xFF);
31 | Data[Offset + 1] = (byte)((Input >> 16) & 0xFF);
32 | Data[Offset + 2] = (byte)((Input >> 8) & 0xFF);
33 | Data[Offset + 3] = (byte)((Input >> 0) & 0xFF);
34 | }
35 |
36 | public static void WriteBEU16(ushort Input, byte[] Data, int Offset)
37 | {
38 | Data[Offset + 0] = (byte)((Input >> 8) & 0xFF);
39 | Data[Offset + 1] = (byte)((Input >> 0) & 0xFF);
40 | }
41 |
42 | public static void WriteStringN(string Input, byte[] Data, int Offset, int Size)
43 | {
44 | byte[] temp = new byte[Size];
45 | for (int i = 0; i < Size; i++)
46 | temp[i] = 0;
47 |
48 | byte[] text = SJISUtil.EncodeStringToSJIS(Input);
49 | Array.Copy(text, temp, Math.Min(text.Length, Size));
50 |
51 | Array.Copy(temp, 0, Data, Offset, Size);
52 |
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/mfs_library/mfs_library.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {8D1CF3E5-BA0F-4790-BA0A-C52B79302DA3}
8 | Library
9 | Properties
10 | mfs_library
11 | mfs_library
12 | v4.6.1
13 | 512
14 | true
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | pdbonly
27 | true
28 | bin\Release\
29 | TRACE
30 | prompt
31 | 4
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/mfs_manager.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.3.32922.545
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mfs_manager", "mfs_manager\mfs_manager.csproj", "{BD3CC0E8-3EA7-4A64-AD41-2D3747F93596}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mfs_gui", "mfs_gui\mfs_gui.csproj", "{48EC8983-43D6-4686-B33D-FD46FEC8CE8D}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mfs_library", "mfs_library\mfs_library.csproj", "{8D1CF3E5-BA0F-4790-BA0A-C52B79302DA3}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "save_manager", "save_manager\save_manager.csproj", "{DBC89E4D-7A97-47FB-AA34-2A7613A3B17C}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Release|Any CPU = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {BD3CC0E8-3EA7-4A64-AD41-2D3747F93596}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {BD3CC0E8-3EA7-4A64-AD41-2D3747F93596}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {BD3CC0E8-3EA7-4A64-AD41-2D3747F93596}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {BD3CC0E8-3EA7-4A64-AD41-2D3747F93596}.Release|Any CPU.Build.0 = Release|Any CPU
24 | {48EC8983-43D6-4686-B33D-FD46FEC8CE8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {48EC8983-43D6-4686-B33D-FD46FEC8CE8D}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {48EC8983-43D6-4686-B33D-FD46FEC8CE8D}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {48EC8983-43D6-4686-B33D-FD46FEC8CE8D}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {8D1CF3E5-BA0F-4790-BA0A-C52B79302DA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {8D1CF3E5-BA0F-4790-BA0A-C52B79302DA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {8D1CF3E5-BA0F-4790-BA0A-C52B79302DA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {8D1CF3E5-BA0F-4790-BA0A-C52B79302DA3}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {DBC89E4D-7A97-47FB-AA34-2A7613A3B17C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {DBC89E4D-7A97-47FB-AA34-2A7613A3B17C}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {DBC89E4D-7A97-47FB-AA34-2A7613A3B17C}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {DBC89E4D-7A97-47FB-AA34-2A7613A3B17C}.Release|Any CPU.Build.0 = Release|Any CPU
36 | EndGlobalSection
37 | GlobalSection(SolutionProperties) = preSolution
38 | HideSolutionNode = FALSE
39 | EndGlobalSection
40 | GlobalSection(ExtensibilityGlobals) = postSolution
41 | SolutionGuid = {83855A69-2379-4A09-88BF-C9EAA8D939A7}
42 | EndGlobalSection
43 | EndGlobal
44 |
--------------------------------------------------------------------------------
/mfs_manager/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/mfs_manager/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.IO;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Text.RegularExpressions;
8 | using mfs_library;
9 |
10 | namespace mfs_manager
11 | {
12 | class Program
13 | {
14 | static void Main(string[] args)
15 | {
16 | Console.OutputEncoding = Encoding.Unicode;
17 | Console.WriteLine("64DD MFS Manager - by LuigiBlood");
18 | if (args.Length < 2)
19 | {
20 | Console.WriteLine("Usage: mfs_manager ");
21 | Console.WriteLine(" can be the following:");
22 | Console.WriteLine(" -d : List all directories with their IDs");
23 | Console.WriteLine(" -f : List all files");
24 | Console.WriteLine(" -e : Extract all files");
25 | Console.WriteLine(" -e : Extract specified file (must start with \"/\")");
26 | Console.WriteLine(" -i : Insert into (Path must start AND end with \"/\")");
27 | Console.WriteLine(" -r : Delete (Path must start with \"/\")");
28 | Console.WriteLine(" -m : Move to AND/OR rename if (Path must start with \"/\")");
29 | }
30 | else if (args.Length >= 2)
31 | {
32 | MFSDisk mfsDisk = new MFSDisk(args[0]);
33 | string savefilename = Path.ChangeExtension(args[0], ".new" + Path.GetExtension(args[0]));
34 |
35 | if (mfsDisk.Disk.Format == LeoDisk.DiskFormat.Invalid)
36 | {
37 | Console.WriteLine("Disk file is invalid.");
38 | return;
39 | }
40 |
41 | if (mfsDisk.Disk.RAMFileSystem != LeoDisk.FileSystem.MFS)
42 | {
43 | Console.WriteLine("Disk file is not using MFS.");
44 | return;
45 | }
46 |
47 | if (args[1].Equals("-d"))
48 | {
49 | //Directory List
50 | Console.WriteLine("Directory List:");
51 | foreach (MFSEntry entry in mfsDisk.RAMVolume.Entries)
52 | {
53 | if (entry.GetType() == typeof(MFSDirectory))
54 | {
55 | Console.WriteLine(((MFSDirectory)entry).DirectoryID + ": " + MFSRAMUtil.GetFullPath(mfsDisk, entry));// + " (" + ((MFSDirectory)entry).CheckShiftJIS() + ")");
56 | }
57 | }
58 | }
59 | else if (args[1].Equals("-f"))
60 | {
61 | //File List
62 | Console.WriteLine("File List:");
63 | foreach (MFSEntry entry in mfsDisk.RAMVolume.Entries)
64 | {
65 | if (entry.GetType() == typeof(MFSFile))
66 | {
67 | Console.WriteLine(MFSRAMUtil.GetFullPath(mfsDisk, entry));
68 | }
69 | }
70 | }
71 | else if (args[1].Equals("-e"))
72 | {
73 | //Extract
74 | if (args.Length > 2)
75 | {
76 | Console.WriteLine("Extract " + args[2]);
77 | byte[] data = MFSRAMUtil.ReadFile(mfsDisk, args[2]);
78 | if (data != null)
79 | {
80 | FileStream fileExt = new FileStream(".\\extract\\" + Path.GetFileName(args[2]), FileMode.Create);
81 | fileExt.Write(data, 0, data.Length);
82 | fileExt.Close();
83 | Console.WriteLine("Done");
84 | }
85 | else
86 | {
87 | Console.WriteLine("Error");
88 | }
89 | }
90 | else
91 | {
92 | foreach (MFSEntry entry in mfsDisk.RAMVolume.Entries)
93 | {
94 | if (entry.GetType() == typeof(MFSFile))
95 | {
96 | Console.WriteLine("Extract " + MFSRAMUtil.GetFullPath(mfsDisk, entry));
97 | byte[] data = MFSRAMUtil.ReadFile(mfsDisk, (MFSFile)entry);
98 | FileStream fileExt = new FileStream(".\\extract\\" + entry.Name + (((MFSFile)entry).Ext != "" ? "." : "") + ((MFSFile)entry).Ext, FileMode.Create);
99 | fileExt.Write(data, 0, data.Length);
100 | fileExt.Close();
101 | }
102 | }
103 | }
104 | }
105 | else if (args[1].Equals("-i") && args.Length > 3)
106 | {
107 | //Insert File
108 | FileStream testAdd = new FileStream(args[2], FileMode.Open);
109 | byte[] testArray = new byte[testAdd.Length];
110 | testAdd.Read(testArray, 0, (int)testAdd.Length);
111 | testAdd.Close();
112 | bool file = false;
113 | if (args[3].StartsWith("/") && args[3].EndsWith("/"))
114 | {
115 | file = MFSRAMUtil.WriteFile(mfsDisk, testArray, args[3] + Path.GetFileName(args[2]));
116 | }
117 | else if (Regex.IsMatch(args[3], "^\\d+$"))
118 | {
119 | file = MFSRAMUtil.WriteFile(mfsDisk, testArray, Path.GetFileName(args[2]), ushort.Parse(args[3]));
120 | }
121 |
122 | if (!file)
123 | Console.WriteLine("Could not insert file");
124 | else
125 | Console.WriteLine("File " + Path.GetFileName(args[2]) + " inserted successfully");
126 | mfsDisk.Save(savefilename);
127 | }
128 | else if (args[1].Equals("-r"))
129 | {
130 | //Delete (-r emove)
131 | if (args.Length > 2)
132 | {
133 | Console.WriteLine("Delete " + args[2]);
134 | if (MFSRAMUtil.DeleteFile(mfsDisk, args[2]))
135 | {
136 | Console.WriteLine("Done");
137 | mfsDisk.Save(savefilename);
138 | }
139 | else
140 | {
141 | Console.WriteLine("Error");
142 | }
143 | }
144 | }
145 | else if (args[1].Equals("-m") && args.Length > 3)
146 | {
147 | //Insert File
148 | if (MFSRAMUtil.MoveFile(mfsDisk, args[2], args[3]))
149 | {
150 | Console.WriteLine("Done");
151 | mfsDisk.Save(savefilename);
152 | }
153 | else
154 | Console.WriteLine("File was not moved/renamed successfully");
155 | }
156 | }
157 | }
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/mfs_manager/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // Les informations générales relatives à un assembly dépendent de
6 | // l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations
7 | // associées à un assembly.
8 | [assembly: AssemblyTitle("mfs_manager")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("mfs_manager")]
13 | [assembly: AssemblyCopyright("Copyright © LuigiBlood 2019")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly
18 | // aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de
19 | // COM, affectez la valeur true à l'attribut ComVisible sur ce type.
20 | [assembly: ComVisible(false)]
21 |
22 | // Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM
23 | [assembly: Guid("bd3cc0e8-3ea7-4a64-ad41-2d3747f93596")]
24 |
25 | // Les informations de version pour un assembly se composent des quatre valeurs suivantes :
26 | //
27 | // Version principale
28 | // Version secondaire
29 | // Numéro de build
30 | // Révision
31 | //
32 | // Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut
33 | // en utilisant '*', comme indiqué ci-dessous :
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.3.0.0")]
36 | [assembly: AssemblyFileVersion("1.3.0.0")]
37 |
--------------------------------------------------------------------------------
/mfs_manager/mfs_manager.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {BD3CC0E8-3EA7-4A64-AD41-2D3747F93596}
8 | Exe
9 | mfs_manager
10 | mfs_manager
11 | v4.6.1
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 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | {8d1cf3e5-ba0f-4790-ba0a-c52b79302da3}
59 | mfs_library
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/save_manager/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/save_manager/MainForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace save_manager
2 | {
3 | partial class MainForm
4 | {
5 | ///
6 | /// Variable nécessaire au concepteur.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Nettoyage des ressources utilisées.
12 | ///
13 | /// true si les ressources managées doivent être supprimées ; sinon, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Code généré par le Concepteur Windows Form
24 |
25 | ///
26 | /// Méthode requise pour la prise en charge du concepteur - ne modifiez pas
27 | /// le contenu de cette méthode avec l'éditeur de code.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.label1 = new System.Windows.Forms.Label();
32 | this.textBoxBaseFile = new System.Windows.Forms.TextBox();
33 | this.buttonBrowse = new System.Windows.Forms.Button();
34 | this.buttonExport = new System.Windows.Forms.Button();
35 | this.buttonImport = new System.Windows.Forms.Button();
36 | this.SuspendLayout();
37 | //
38 | // label1
39 | //
40 | this.label1.AutoSize = true;
41 | this.label1.Location = new System.Drawing.Point(12, 9);
42 | this.label1.Name = "label1";
43 | this.label1.Size = new System.Drawing.Size(143, 13);
44 | this.label1.TabIndex = 0;
45 | this.label1.Text = "Base 64DD Disk / RAM File:";
46 | //
47 | // textBoxBaseFile
48 | //
49 | this.textBoxBaseFile.Location = new System.Drawing.Point(15, 25);
50 | this.textBoxBaseFile.Name = "textBoxBaseFile";
51 | this.textBoxBaseFile.ReadOnly = true;
52 | this.textBoxBaseFile.Size = new System.Drawing.Size(236, 20);
53 | this.textBoxBaseFile.TabIndex = 1;
54 | //
55 | // buttonBrowse
56 | //
57 | this.buttonBrowse.Location = new System.Drawing.Point(257, 24);
58 | this.buttonBrowse.Name = "buttonBrowse";
59 | this.buttonBrowse.Size = new System.Drawing.Size(75, 22);
60 | this.buttonBrowse.TabIndex = 2;
61 | this.buttonBrowse.Text = "Browse...";
62 | this.buttonBrowse.UseVisualStyleBackColor = true;
63 | this.buttonBrowse.Click += new System.EventHandler(this.buttonBrowse_Click);
64 | //
65 | // buttonExport
66 | //
67 | this.buttonExport.Location = new System.Drawing.Point(15, 91);
68 | this.buttonExport.Name = "buttonExport";
69 | this.buttonExport.Size = new System.Drawing.Size(93, 23);
70 | this.buttonExport.TabIndex = 3;
71 | this.buttonExport.Text = "Export RAM...";
72 | this.buttonExport.UseVisualStyleBackColor = true;
73 | this.buttonExport.Click += new System.EventHandler(this.buttonExport_Click);
74 | //
75 | // buttonImport
76 | //
77 | this.buttonImport.Location = new System.Drawing.Point(239, 91);
78 | this.buttonImport.Name = "buttonImport";
79 | this.buttonImport.Size = new System.Drawing.Size(93, 23);
80 | this.buttonImport.TabIndex = 4;
81 | this.buttonImport.Text = "Import RAM...";
82 | this.buttonImport.UseVisualStyleBackColor = true;
83 | this.buttonImport.Click += new System.EventHandler(this.buttonImport_Click);
84 | //
85 | // MainForm
86 | //
87 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
88 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
89 | this.ClientSize = new System.Drawing.Size(343, 125);
90 | this.Controls.Add(this.buttonImport);
91 | this.Controls.Add(this.buttonExport);
92 | this.Controls.Add(this.buttonBrowse);
93 | this.Controls.Add(this.textBoxBaseFile);
94 | this.Controls.Add(this.label1);
95 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
96 | this.Name = "MainForm";
97 | this.Text = "64DD Save Manager";
98 | this.ResumeLayout(false);
99 | this.PerformLayout();
100 |
101 | }
102 |
103 | #endregion
104 |
105 | private System.Windows.Forms.Label label1;
106 | private System.Windows.Forms.TextBox textBoxBaseFile;
107 | private System.Windows.Forms.Button buttonBrowse;
108 | private System.Windows.Forms.Button buttonExport;
109 | private System.Windows.Forms.Button buttonImport;
110 | }
111 | }
112 |
113 |
--------------------------------------------------------------------------------
/save_manager/MainForm.cs:
--------------------------------------------------------------------------------
1 | using mfs_library;
2 | using System;
3 | using System.IO;
4 | using System.Collections.Generic;
5 | using System.ComponentModel;
6 | using System.Data;
7 | using System.Drawing;
8 | using System.Linq;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 | using System.Windows.Forms;
12 | using System.Linq.Expressions;
13 |
14 | namespace save_manager
15 | {
16 | public partial class MainForm : Form
17 | {
18 | public MainForm()
19 | {
20 | InitializeComponent();
21 | }
22 |
23 | private void buttonBrowse_Click(object sender, EventArgs e)
24 | {
25 | OpenFileDialog ofs = new OpenFileDialog();
26 | ofs.Title = "Open Base 64DD Disk / RAM File...";
27 | ofs.Multiselect = false;
28 | ofs.Filter = "All Supported Files (*.ndd, *.ndr, *.ram, *.n64, *.z64, *.disk)|*.ndd;*.ndr;*.ram;*.n64;*.z64;*.disk|64DD RAM Area Image (*.ram)|*.ram|64DD Disk Image (*.ndd, *.ndr, *.disk)|*.ndd;*.ndr;*.disk|N64 Cartridge Port Image (*.n64, *.z64)|*.n64;*.z64|All files|*.*";
29 | if (ofs.ShowDialog() == DialogResult.OK)
30 | {
31 | var error = Program.Load(ofs.FileName);
32 | if (error == Program.DiskError.NotDiskFile)
33 | {
34 | MessageBox.Show("This file is not a disk file.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
35 | return;
36 | }
37 | else if (error == Program.DiskError.NoRAMArea)
38 | {
39 | MessageBox.Show("This disk does not contain a RAM Area.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
40 | return;
41 | }
42 | else if (error == Program.DiskError.FileNotExist)
43 | {
44 | MessageBox.Show("This file does not exist.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
45 | return;
46 | }
47 | textBoxBaseFile.Text = Program.Disk.Filename;
48 | }
49 | }
50 |
51 | private void buttonExport_Click(object sender, EventArgs e)
52 | {
53 | if (Program.Disk == null)
54 | {
55 | MessageBox.Show("Please load a disk file first.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
56 | return;
57 | }
58 |
59 | SaveFileDialog sfd = new SaveFileDialog();
60 | sfd.Title = "Export RAM File...";
61 | sfd.Filter = "64DD RAM Area Image (*.ram)|*.ram";
62 | if (sfd.ShowDialog() == DialogResult.OK)
63 | {
64 | bool saveError = false;
65 | try
66 | {
67 | Program.ExportRAM(sfd.FileName);
68 | }
69 | catch
70 | {
71 | saveError = true;
72 | }
73 |
74 | if (!saveError)
75 | {
76 | MessageBox.Show("File has been saved.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
77 | }
78 | }
79 | }
80 |
81 | private void buttonImport_Click(object sender, EventArgs e)
82 | {
83 | if (Program.Disk == null)
84 | {
85 | MessageBox.Show("Please load a disk file first.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
86 | return;
87 | }
88 |
89 | OpenFileDialog ofs = new OpenFileDialog();
90 | ofs.Title = "Import 64DD Disk / RAM File...";
91 | ofs.Multiselect = false;
92 | ofs.Filter = "All Supported Files (*.ndd, *.ndr, *.ram, *.n64, *.z64, *.disk)|*.ndd;*.ndr;*.ram;*.n64;*.z64;*.disk|64DD RAM Area Image (*.ram)|*.ram|64DD Disk Image (*.ndd, *.ndr, *.disk)|*.ndd;*.ndr;*.disk|N64 Cartridge Port Image (*.n64, *.z64)|*.n64;*.z64|All files|*.*";
93 | if (ofs.ShowDialog() == DialogResult.OK)
94 | {
95 | var error = Program.ImportRAM(ofs.FileName);
96 | if (error == Program.DiskError.NotDiskFile)
97 | {
98 | MessageBox.Show("This file is not a disk file.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
99 | return;
100 | }
101 | else if (error == Program.DiskError.NoRAMArea)
102 | {
103 | MessageBox.Show("This disk does not contain a RAM Area.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
104 | return;
105 | }
106 | else if (error == Program.DiskError.FileNotExist)
107 | {
108 | MessageBox.Show("This file does not exist.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
109 | return;
110 | }
111 | else if (error == Program.DiskError.Mismatch)
112 | {
113 | MessageBox.Show("Both disks' RAM Area format do not match.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
114 | return;
115 | }
116 |
117 |
118 | SaveFileDialog sfd = new SaveFileDialog();
119 | sfd.Title = "Save Modified Disk...";
120 | switch (Program.Disk.Format)
121 | {
122 | case LeoDisk.DiskFormat.SDK:
123 | case LeoDisk.DiskFormat.MAME:
124 | sfd.Filter = "64DD Disk Image (*.ndd, *.ndr, *.disk)|*.ndd;*.ndr;*.disk";
125 | break;
126 | case LeoDisk.DiskFormat.RAM:
127 | sfd.Filter = "64DD RAM Area Image (*.ram)|*.ram";
128 | break;
129 | case LeoDisk.DiskFormat.N64:
130 | sfd.Filter = "N64 Cartridge Port Image (*.n64, *.z64)|*.n64;*.z64";
131 | break;
132 | default:
133 | return;
134 | }
135 |
136 | if (sfd.ShowDialog() == DialogResult.OK)
137 | {
138 | bool saveError = false;
139 | try
140 | {
141 | Program.Disk.Save(sfd.FileName);
142 | }
143 | catch
144 | {
145 | saveError = true;
146 | }
147 |
148 | if (!saveError)
149 | {
150 | MessageBox.Show("File has been saved.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
151 | }
152 | }
153 | }
154 | }
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/save_manager/MainForm.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 |
--------------------------------------------------------------------------------
/save_manager/Program.cs:
--------------------------------------------------------------------------------
1 | using mfs_library;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using System.Windows.Forms;
8 |
9 | namespace save_manager
10 | {
11 | internal static class Program
12 | {
13 | ///
14 | /// Point d'entrée principal de l'application.
15 | ///
16 | [STAThread]
17 | static void Main()
18 | {
19 | Application.EnableVisualStyles();
20 | Application.SetCompatibleTextRenderingDefault(false);
21 | Application.Run(new MainForm());
22 | }
23 |
24 | public static LeoDisk Disk;
25 |
26 | public enum DiskError
27 | {
28 | Success,
29 | NotDiskFile,
30 | NoRAMArea,
31 | FileNotExist,
32 | Mismatch
33 | }
34 |
35 | public static DiskError Load(string filepath)
36 | {
37 | LeoDisk _disk;
38 | var error = Load(filepath, out _disk);
39 |
40 | if (error == DiskError.Success)
41 | Disk = _disk;
42 |
43 | return error;
44 | }
45 |
46 | public static DiskError Load(string filepath, out LeoDisk _disk)
47 | {
48 | _disk = null;
49 | if (!File.Exists(filepath))
50 | return DiskError.FileNotExist;
51 |
52 | _disk = new LeoDisk(filepath);
53 | if (_disk.Format == LeoDisk.DiskFormat.Invalid)
54 | return DiskError.NotDiskFile;
55 | if (_disk.DiskType >= 6)
56 | return DiskError.NoRAMArea;
57 |
58 | return DiskError.Success;
59 | }
60 |
61 | public static void ExportRAM(string filepath)
62 | {
63 | if (Disk == null) return;
64 |
65 | File.WriteAllBytes(filepath, Disk.GetRAMAreaArray());
66 | }
67 |
68 | public static DiskError ImportRAM(string filepath)
69 | {
70 | LeoDisk _disk;
71 | var error = Load(filepath, out _disk);
72 |
73 | if (error != DiskError.Success) return error;
74 | if (_disk.DiskType != Disk.DiskType) return DiskError.Mismatch;
75 |
76 | for (var lba = Leo.RamStartLBA[_disk.DiskType]; lba < Leo.SIZE_LBA; lba++)
77 | {
78 | Disk.WriteLBA(lba, _disk.ReadLBA(lba));
79 | }
80 |
81 | return DiskError.Success;
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/save_manager/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // Les informations générales relatives à un assembly dépendent de
6 | // l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations
7 | // associées à un assembly.
8 | [assembly: AssemblyTitle("64DD Save Manager")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("64DD Save Manager")]
13 | [assembly: AssemblyCopyright("Copyright © LuigiBlood 2022")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly
18 | // aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de
19 | // COM, affectez la valeur true à l'attribut ComVisible sur ce type.
20 | [assembly: ComVisible(false)]
21 |
22 | // Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM
23 | [assembly: Guid("dbc89e4d-7a97-47fb-aa34-2a7613a3b17c")]
24 |
25 | // Les informations de version pour un assembly se composent des quatre valeurs suivantes :
26 | //
27 | // Version principale
28 | // Version secondaire
29 | // Numéro de build
30 | // Révision
31 | //
32 | // Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut
33 | // en utilisant '*', comme indiqué ci-dessous :
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/save_manager/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // Ce code a été généré par un outil.
4 | // Version du runtime :4.0.30319.42000
5 | //
6 | // Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si
7 | // le code est régénéré.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace save_manager.Properties
12 | {
13 |
14 |
15 | ///
16 | /// Une classe de ressource fortement typée destinée, entre autres, à la consultation des chaînes localisées.
17 | ///
18 | // Cette classe a été générée automatiquement par la classe StronglyTypedResourceBuilder
19 | // à l'aide d'un outil, tel que ResGen ou Visual Studio.
20 | // Pour ajouter ou supprimer un membre, modifiez votre fichier .ResX, puis réexécutez ResGen
21 | // avec l'option /str ou régénérez votre projet VS.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// Retourne l'instance ResourceManager mise en cache utilisée par cette classe.
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("save_manager.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// Remplace la propriété CurrentUICulture du thread actuel pour toutes
56 | /// les recherches de ressources à l'aide de cette classe de ressource fortement typée.
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/save_manager/Properties/Resources.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 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/save_manager/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace save_manager.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/save_manager/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/save_manager/save_manager.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {DBC89E4D-7A97-47FB-AA34-2A7613A3B17C}
8 | WinExe
9 | save_manager
10 | save_manager
11 | v4.6.1
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 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | Form
51 |
52 |
53 | MainForm.cs
54 |
55 |
56 |
57 |
58 | MainForm.cs
59 |
60 |
61 | ResXFileCodeGenerator
62 | Resources.Designer.cs
63 | Designer
64 |
65 |
66 | True
67 | Resources.resx
68 |
69 |
70 | SettingsSingleFileGenerator
71 | Settings.Designer.cs
72 |
73 |
74 | True
75 | Settings.settings
76 | True
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | {8D1CF3E5-BA0F-4790-BA0A-C52B79302DA3}
85 | mfs_library
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------