Skip to content

Commit 52d70f0

Browse files
committed
Initial Commit
1 parent c2cf579 commit 52d70f0

File tree

175 files changed

+13734
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

175 files changed

+13734
-0
lines changed

LICENSE

Lines changed: 674 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# pkNX
2+
pkNX... for lack of a better name!

pkNX.Containers/Container.cs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using System;
2+
using System.IO;
3+
4+
namespace pkNX.Containers
5+
{
6+
public static class Container
7+
{
8+
/// <summary>
9+
/// Gets a new <see cref="IFileContainer"/> for the provided <see cref="path"/> and type.
10+
/// </summary>
11+
/// <param name="path">File location</param>
12+
/// <param name="t">File type</param>
13+
public static IFileContainer GetContainer(string path, ContainerType t)
14+
{
15+
switch (t)
16+
{
17+
case ContainerType.GARC: return new GARC(path);
18+
case ContainerType.Mini: return MiniUtil.GetMini(path);
19+
case ContainerType.SARC: return new SARC(path);
20+
case ContainerType.Folder: return new FolderContainer(path);
21+
case ContainerType.SingleFile: return new SingleFileContainer(path);
22+
default:
23+
throw new ArgumentOutOfRangeException(nameof(t), t, null);
24+
}
25+
}
26+
27+
/// <summary>
28+
/// Gets a <see cref="IFileContainer"/> for the stream.
29+
/// </summary>
30+
/// <param name="path">Path to the binary data</param>
31+
public static IFileContainer GetContainer(string path)
32+
{
33+
var fs = new FileStream(path, FileMode.Open);
34+
var container = GetContainer(fs);
35+
if (!(container is LargeContainer)) // not kept
36+
fs.Dispose();
37+
if (container == null)
38+
return null;
39+
40+
container.FilePath = path;
41+
return container;
42+
}
43+
44+
/// <summary>
45+
/// Gets a <see cref="IFileContainer"/> for the stream.
46+
/// </summary>
47+
/// <param name="stream">Stream for the binary data</param>
48+
public static IFileContainer GetContainer(Stream stream)
49+
{
50+
BinaryReader br = new BinaryReader(stream);
51+
var container = GetContainer(br);
52+
if (!(container is LargeContainer)) // not kept
53+
br.Dispose();
54+
return container;
55+
}
56+
57+
/// <summary>
58+
/// Gets a <see cref="IFileContainer"/> for the stream within the <see cref="BinaryReader"/>.
59+
/// </summary>
60+
/// <param name="br">Reader for the binary data</param>
61+
public static IFileContainer GetContainer(BinaryReader br)
62+
{
63+
IFileContainer container;
64+
if ((container = GARC.GetGARC(br)) != null)
65+
return container;
66+
if ((container = MiniUtil.GetMini(br)) != null)
67+
return container;
68+
if ((container = SARC.GetSARC(br)) != null)
69+
return container;
70+
return null;
71+
}
72+
}
73+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using System;
2+
// ReSharper disable ClassNeverInstantiated.Global
3+
// ReSharper disable EventNeverSubscribedTo.Global
4+
5+
namespace pkNX.Containers
6+
{
7+
public sealed class ContainerHandler
8+
{
9+
public event EventHandler<FileCountDeterminedEventArgs> FileCountDetermined;
10+
public event EventHandler<FileProgressedEventArgs> FileProgressed;
11+
12+
private int count;
13+
14+
public void Initialize(int total)
15+
{
16+
count = total;
17+
var args = new FileCountDeterminedEventArgs {Total = total};
18+
FileCountDetermined?.Invoke(null, args);
19+
}
20+
21+
public void StepFile(int ctr, int total = -1, string fileName = null)
22+
{
23+
if (total < 0)
24+
total = count;
25+
var args = new FileProgressedEventArgs {Current = ctr, Total = total, CurrentFile = fileName};
26+
FileProgressed?.Invoke(null, args);
27+
}
28+
}
29+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System;
2+
3+
namespace pkNX.Containers
4+
{
5+
public class FileCountDeterminedEventArgs : EventArgs
6+
{
7+
public int Total { get; set; }
8+
}
9+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System;
2+
3+
namespace pkNX.Containers
4+
{
5+
public class FileProgressedEventArgs : EventArgs
6+
{
7+
public int Current { get; set; }
8+
public int Total { get; set; }
9+
public string CurrentFile { get; set; }
10+
}
11+
}

pkNX.Containers/ContainerParent.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace pkNX.Containers
2+
{
3+
public enum ContainerParent
4+
{
5+
/// <summary>
6+
/// File is located in the RomFS.
7+
/// </summary>
8+
RomFS,
9+
10+
/// <summary>
11+
/// File is located in the ExeFS.
12+
/// </summary>
13+
ExeFS,
14+
}
15+
}

pkNX.Containers/ContainerType.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace pkNX.Containers
2+
{
3+
public enum ContainerType
4+
{
5+
GARC,
6+
Mini,
7+
SARC,
8+
Folder,
9+
SingleFile,
10+
}
11+
}

pkNX.Containers/FolderContainer.cs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
using System.Collections.Generic;
2+
using System.IO;
3+
using System.Linq;
4+
using System.Threading;
5+
using System.Threading.Tasks;
6+
7+
namespace pkNX.Containers
8+
{
9+
public class FolderContainer : IFileContainer
10+
{
11+
private readonly List<string> Paths = new List<string>();
12+
private readonly List<byte[]> Data = new List<byte[]>();
13+
private readonly List<bool> TrackModify = new List<bool>();
14+
15+
public FolderContainer() { }
16+
public FolderContainer(IEnumerable<string> files) => AddFiles(files);
17+
18+
public FolderContainer(string path)
19+
{
20+
FilePath = path;
21+
AddFiles(Directory.GetFiles(path, "*", SearchOption.AllDirectories));
22+
}
23+
24+
public void AddFile(string file, byte[] data = null)
25+
{
26+
Paths.Add(file);
27+
Data.Add(data);
28+
TrackModify.Add(false);
29+
}
30+
31+
public void AddFiles(IEnumerable<string> files)
32+
{
33+
foreach (var f in files)
34+
AddFile(f);
35+
}
36+
37+
public byte[] GetFileData(string file)
38+
{
39+
var index = Paths.IndexOf(file);
40+
if (index < 0)
41+
return null;
42+
return Data[index] ?? (Data[index] = File.ReadAllBytes(file));
43+
}
44+
45+
public byte[] GetFileData(int index)
46+
{
47+
if (index < 0 || Data.Count >= index)
48+
return null;
49+
return Data[index] ?? (Data[index] = File.ReadAllBytes(Paths[index]));
50+
}
51+
52+
public byte[] this[int index]
53+
{
54+
get => GetFileData(index);
55+
set
56+
{
57+
if (value != null && Data[index] != null)
58+
TrackModify[index] = value.SequenceEqual(Data[index]);
59+
Data[index] = value;
60+
}
61+
}
62+
63+
public string FilePath { get; set; }
64+
public bool Modified => TrackModify.Count != 0;
65+
public int Count => Paths.Count;
66+
67+
public Task<byte[][]> GetFiles() => new Task<byte[][]>(() => Paths.Select(File.ReadAllBytes).ToArray());
68+
public Task<byte[]> GetFile(int file, int subFile = 0) => new Task<byte[]>(() => this[file]);
69+
public Task SetFile(int file, byte[] value, int subFile = 0) => new Task(() => this[file] = value);
70+
public Task SaveAs(string path, ContainerHandler handler, CancellationToken token) => new Task(SaveAll);
71+
72+
private void SaveAll()
73+
{
74+
for (int i = 0; i < Paths.Count; i++)
75+
{
76+
if (!TrackModify[i])
77+
continue;
78+
var data = Data[i];
79+
if (data == null)
80+
continue;
81+
File.WriteAllBytes(Paths[i], data);
82+
}
83+
}
84+
85+
public void Dump(string path, ContainerHandler handler)
86+
{
87+
SaveAll(); // there's really nothing to dump, just save any modified
88+
}
89+
}
90+
}

pkNX.Containers/GARC/FATB.cs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using System.Collections.Generic;
2+
using System.IO;
3+
4+
namespace pkNX.Containers
5+
{
6+
internal class FATB
7+
{
8+
private const uint MAGIC = 0x46415442;
9+
10+
private readonly uint Magic = MAGIC;
11+
private readonly int HeaderSize = 0xC;
12+
private readonly ushort EntryCount;
13+
private readonly short Padding = -1;
14+
15+
private FATBEntry[] Entries { get; }
16+
public FATBEntry this[int index] => Entries[index];
17+
18+
public FATB(BinaryReader br, int DataOffset)
19+
{
20+
Magic = br.ReadUInt32();
21+
HeaderSize = br.ReadInt32();
22+
EntryCount = br.ReadUInt16();
23+
Padding = br.ReadInt16();
24+
25+
Entries = new FATBEntry[EntryCount];
26+
for (int i = 0; i < EntryCount; i++)
27+
Entries[i] = new FATBEntry(br, DataOffset);
28+
}
29+
30+
public FATB(IReadOnlyList<string> files)
31+
{
32+
EntryCount = (ushort)files.Count;
33+
Entries = new FATBEntry[EntryCount];
34+
for (int i = 0; i < EntryCount; i++)
35+
{
36+
if (!Directory.Exists(files[i]))
37+
Entries[i] = new FATBEntry(files[i]);
38+
else
39+
Entries[i] = new FATBEntry(Directory.GetFiles(files[i]));
40+
}
41+
}
42+
43+
public void Write(BinaryWriter bw)
44+
{
45+
bw.Write(Magic);
46+
bw.Write(HeaderSize);
47+
bw.Write(EntryCount);
48+
bw.Write(Padding);
49+
foreach (var entry in Entries)
50+
entry.Write(bw);
51+
// sub entry writing handled separately
52+
}
53+
}
54+
}

0 commit comments

Comments
 (0)