├── .gitmodules
├── .editorconfig
├── PkgEditor
├── pkgtool.ico
├── Images
│ ├── spinner.gif
│ ├── File_large.png
│ ├── File_small.png
│ ├── Folder_large.png
│ └── Folder_small.png
├── app.config
├── Properties
│ ├── Settings.settings
│ ├── Settings.Designer.cs
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ └── Resources.resx
├── Program.cs
├── PasscodeEntry.cs
├── LogWindow.cs
├── Views
│ ├── View.cs
│ ├── PFSView.Designer.cs
│ ├── ObjectView.Designer.cs
│ ├── PFSView.cs
│ ├── ObjectView.cs
│ ├── CryptoDebug.cs
│ ├── CryptoDebug.resx
│ ├── ObjectView.resx
│ ├── PFSView.resx
│ ├── FileView.cs
│ ├── PkgView.resx
│ └── SFOView.resx
├── LogWindow.Designer.cs
├── ValidationDialog.cs
├── KeyDB.cs
├── PasscodeEntry.Designer.cs
├── ValidationDialog.Designer.cs
├── LogWindow.resx
├── PasscodeEntry.resx
└── ValidationDialog.resx
├── idx.bt
├── README.md
├── LibOrbisPkg
├── Kimie
│ ├── Count.cs
│ └── Counter.cs
├── Util
│ ├── Extensions.cs
│ ├── OffsetStream.cs
│ ├── ReaderBase.cs
│ ├── SubStream.cs
│ ├── WriterBase.cs
│ ├── MersenneTwister.cs
│ └── XtsBlockTransform.cs
├── Rif
│ ├── LicenseInfo.cs
│ └── LicenseDat.cs
├── Properties
│ └── AssemblyInfo.cs
├── PFS
│ ├── PFSCWriter.cs
│ ├── FlatPathTable.cs
│ ├── PfsProperties.cs
│ ├── XtsDecryptReader.cs
│ ├── PFSCReader.cs
│ └── FSTree.cs
├── PlayGo
│ ├── Manifest.cs
│ └── ChunkDat.cs
├── PKG
│ ├── PkgProperties.cs
│ ├── PkgWriter.cs
│ └── PkgReader.cs
├── LibOrbisPkg.csproj
└── GP4
│ └── Gp4Validator.cs
├── Rif.bt
├── SFO.bt
├── CollisionResolver.bt
├── PFSC.bt
├── rifa.bt
├── LibOrbisPkg.Core.sln
├── PlaygoChunkDat.bt
├── LibOrbisPkg.sln
├── .gitattributes
├── appveyor.yml
└── .gitignore
/.gitmodules:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | indent_style = space
3 | indent_size = 2
4 | end_of_line = crlf
5 |
--------------------------------------------------------------------------------
/PkgEditor/pkgtool.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KimieStar/Pkg-Editor-2023/HEAD/PkgEditor/pkgtool.ico
--------------------------------------------------------------------------------
/PkgEditor/Images/spinner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KimieStar/Pkg-Editor-2023/HEAD/PkgEditor/Images/spinner.gif
--------------------------------------------------------------------------------
/PkgEditor/Images/File_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KimieStar/Pkg-Editor-2023/HEAD/PkgEditor/Images/File_large.png
--------------------------------------------------------------------------------
/PkgEditor/Images/File_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KimieStar/Pkg-Editor-2023/HEAD/PkgEditor/Images/File_small.png
--------------------------------------------------------------------------------
/PkgEditor/Images/Folder_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KimieStar/Pkg-Editor-2023/HEAD/PkgEditor/Images/Folder_large.png
--------------------------------------------------------------------------------
/PkgEditor/Images/Folder_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KimieStar/Pkg-Editor-2023/HEAD/PkgEditor/Images/Folder_small.png
--------------------------------------------------------------------------------
/PkgEditor/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/idx.bt:
--------------------------------------------------------------------------------
1 | LittleEndian();
2 |
3 | char magic[4];
4 | int num;
5 | char i;
6 | char title[23];
7 | struct {
8 | char name[16];
9 | int64 offset;
10 | int64 size;
11 | char unk;
12 | char unk2;
13 | char hmac[8];
14 | char pad[6];
15 | } rifs[num];
--------------------------------------------------------------------------------
/PkgEditor/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This is an enhanced version of maxton's / LibOrbisPkg\
2 | And some features are going to be added\
3 | :p
4 |
5 | # Fixed Bugs
6 | App won't freeze anymore when extracting.
7 |
8 |
9 |
10 | # New Features
11 |
12 | ## Progress Bar
13 | To check on your progress ;)
14 | 
15 |
16 |
--------------------------------------------------------------------------------
/LibOrbisPkg/Kimie/Count.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace LibOrbisPkg.Kimie
7 | {
8 | public static class Count
9 | {
10 | private static int count = new int();
11 | private static int MaxCount = new int();
12 |
13 | public static int Count1 { get => count; set => count = value; }
14 | public static int MaxCount1 { get => MaxCount; set => MaxCount = value; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Rif.bt:
--------------------------------------------------------------------------------
1 | BigEndian();
2 | char signature[4];
3 | uint16 version;
4 | int16 unk_06;
5 | int64 PsnId;
6 | int64 startTime;
7 | int64 EndTime;
8 | char contentId[48];
9 | uint16 license_type;
10 | uint16 drm_type;
11 | uint16 content_type;
12 | uint16 SKU_flag;
13 | uint flags;
14 | uint unk_5C;
15 | uint unk_60;
16 | uint unk_64;
17 | uint unk_flag;
18 | uint16 unk_6c;
19 | uint16 unk_6e;
20 | char pad[464];
21 | byte disc_key[32];
22 | byte secret_iv[16];
23 | byte secret[144];
24 | byte sig[256];
--------------------------------------------------------------------------------
/SFO.bt:
--------------------------------------------------------------------------------
1 | enum param_fmt {
2 | utf8_special = 0x4,
3 | utf8 = 0x204,
4 | integer = 0x404
5 | };
6 |
7 | char magic[4];
8 | int version;
9 | int key_table_start;
10 | int data_table_start;
11 | int num_entries;
12 | struct {
13 | uint16 keyOffset; //offset of keytable + keyOffset
14 | param_fmt format; //enum (see below)
15 | uint32 paramLen;
16 | uint32 paramMaxLen;
17 | uint32 dataOffset; //offset of datatable + dataOffset
18 | } indices[num_entries];
19 | FSeek(key_table_start);
--------------------------------------------------------------------------------
/PkgEditor/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Windows.Forms;
5 |
6 | namespace PkgEditor
7 | {
8 | static class Program
9 | {
10 | ///
11 | /// The main entry point for the application.
12 | ///
13 | [STAThread]
14 | static void Main()
15 | {
16 | Application.EnableVisualStyles();
17 | Application.SetCompatibleTextRenderingDefault(false);
18 | Application.Run(new MainWin());
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/CollisionResolver.bt:
--------------------------------------------------------------------------------
1 | LittleEndian();
2 |
3 | typedef struct {
4 | local int64 pos = FTell();
5 | uint inode;
6 | uint type;
7 | uint namelen;
8 | uint entsize;
9 | char name[namelen];
10 | char pad[entsize - (FTell() - pos)];
11 | } Entry;
12 |
13 | while (!FEof())
14 | {
15 | Entry e;
16 | if(ReadInt() == 0)
17 | {
18 | while(!FEof()){
19 | FSeek(FTell() + 4);
20 | if(ReadInt() != 0)
21 | {
22 | break;
23 | }
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/PkgEditor/PasscodeEntry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 |
11 | namespace PkgEditor
12 | {
13 | public partial class PasscodeEntry : Form
14 | {
15 | public PasscodeEntry(string prompt = "Please enter the package's passcode.", int length = 32)
16 | {
17 | InitializeComponent();
18 | label1.Text = prompt;
19 | textBox1.MaxLength = length;
20 | }
21 | public string Passcode => textBox1.Text;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/PFSC.bt:
--------------------------------------------------------------------------------
1 | LittleEndian();
2 | char Magic[4];
3 | int unk; // zero
4 | int unk; // 2 or 6
5 | int blocksz;
6 | uint64 blocksz2; // always the same as blocksz?
7 | uint64 block_offsets; // start of block offsets
8 | uint64 data_start; // start of compressed sectors
9 | uint64 data_length; // uncompressed image size
10 |
11 | FSeek(block_offsets);
12 | local uint64 num_blocks = data_length / blocksz;
13 | uint64 blocks[num_blocks + 1];
14 |
15 | FSeek(blocks[0]);
16 | local uint64 i = 0;
17 | struct {
18 | for(i = 0; i < num_blocks; i++)
19 | struct {
20 | byte data[blocks[i + 1] - blocks[i]];
21 | } sector;
22 | } sectors;
--------------------------------------------------------------------------------
/rifa.bt:
--------------------------------------------------------------------------------
1 | typedef struct {
2 | #include "Rif.bt"
3 | } Rif;
4 |
5 | string approx_date(int64 time) {
6 | string ret;
7 | local int64 secs_per_year = 31557600;
8 | local int64 secs_per_month = secs_per_year / 12;
9 | SPrintf(ret, "%4d-%02d", (time / secs_per_year)+1970, (time / secs_per_month) % 12 + 1);
10 | return ret;
11 | }
12 |
13 | string RIF_READ(Rif &r) {
14 | string ret;
15 | SPrintf(ret, "V%d T%x U%d C%d %s - %s",
16 | r.version,
17 | r.license_type,
18 | r.unk_flag,
19 | r.content_type,
20 | approx_date(r.startTime),
21 | r.contentId);
22 | return ret;
23 | }
24 |
25 | BigEndian();
26 | if (ReadInt() == 0x72696661) {
27 | char rifaMagic[4];
28 | char ServiceID[0x14];
29 | FSeek(0x400);
30 | while(!FEof()) {
31 | Rif rif;
32 | }
33 | }
--------------------------------------------------------------------------------
/PkgEditor/LogWindow.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Windows.Forms;
9 | using System.IO;
10 |
11 | namespace PkgEditor
12 | {
13 | public partial class LogWindow : Form
14 | {
15 | public LogWindow()
16 | {
17 | InitializeComponent();
18 | writer = new LogWriter(logBox);
19 | }
20 | private TextWriter writer;
21 |
22 | private class LogWriter : TextWriter
23 | {
24 | private TextBox box;
25 | public LogWriter(TextBox b) { box = b; }
26 | public override void Write(char value)
27 | {
28 | box.Text += value;
29 | }
30 | public override void Write(string value)
31 | {
32 | box.Text += value;
33 | }
34 | public override Encoding Encoding
35 | {
36 | get { return Encoding.ASCII; }
37 | }
38 | }
39 |
40 | public TextWriter GetWriter() => writer;
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/PkgEditor/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 PkgEditor.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.7.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/LibOrbisPkg/Util/Extensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace LibOrbisPkg.Util
5 | {
6 | public static class DictionaryExtensions
7 | {
8 | public static V GetOrDefault(this Dictionary d, K key, V def = default(V))
9 | {
10 | if (d.ContainsKey(key)) return d[key];
11 | return def;
12 | }
13 | }
14 |
15 | public static class ArrayExtensions
16 | {
17 | public static T[] Fill(this T[] arr, T val)
18 | {
19 | for (var i = 0; i < arr.Length; i++)
20 | {
21 | arr[i] = val;
22 | }
23 | return arr;
24 | }
25 | }
26 |
27 | public static class ByteArrayExtensions
28 | {
29 | public static string ToHexCompact(this byte[] b)
30 | {
31 | var sb = new System.Text.StringBuilder();
32 | foreach (var x in b) sb.AppendFormat("{0:X2}", x);
33 | return sb.ToString();
34 | }
35 | }
36 | #if !CORE
37 | public static class TupleExtension
38 | {
39 | public static void Deconstruct(this Tuple twople, out T1 item1, out T2 item2)
40 | {
41 | item1 = twople.Item1;
42 | item2 = twople.Item2;
43 | }
44 | }
45 | #endif
46 | }
47 |
--------------------------------------------------------------------------------
/LibOrbisPkg/Rif/LicenseInfo.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Text;
3 | using LibOrbisPkg.PKG;
4 | using LibOrbisPkg.Util;
5 |
6 | namespace LibOrbisPkg.Rif
7 | {
8 | class LicenseInfo
9 | {
10 | public LicenseInfo(string contentId, ContentType type, byte[] entitlement)
11 | {
12 | ContentId = contentId;
13 | ContentType = type;
14 | EntitlementKey = entitlement;
15 | Unknown_40 = ContentType == ContentType.AL ? 1 : 0;
16 | Unknown_48 = 0;
17 | Unknown_4C = 1;
18 | }
19 | public string ContentId;
20 | public byte[] EntitlementKey;
21 | public int Unknown_40;
22 | public ContentType ContentType = ContentType.AC;
23 | public int Unknown_48;
24 | public int Unknown_4C;
25 | }
26 |
27 | class LicenseInfoWriter : WriterBase
28 | {
29 | public LicenseInfoWriter(Stream stream) : base(true, stream) { }
30 |
31 | public void Write(LicenseInfo dat)
32 | {
33 | Write(Encoding.ASCII.GetBytes(dat.ContentId));
34 | Write(new byte[12]);
35 | Write(dat.EntitlementKey ?? new byte[16]);
36 | Write(dat.Unknown_40);
37 | Write((int)dat.ContentType);
38 | Write(dat.Unknown_48);
39 | Write(dat.Unknown_4C);
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/PkgEditor/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("PkgEditor")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("PkgEditor")]
13 | [assembly: AssemblyCopyright("Copyright © 2018-2020 Maxton")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("60b5d407-d849-4b84-8a5e-d740ea1f8125")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("0.2.0.0")]
36 | [assembly: AssemblyFileVersion("0.2.0.0")]
37 |
--------------------------------------------------------------------------------
/LibOrbisPkg/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("LibOrbisPkg")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("LibOrbisPkg")]
13 | [assembly: AssemblyCopyright("Copyright © 2018-2020 Maxton")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("b053f491-ff0f-4cbb-b03b-520591bb0441")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("0.2.0.0")]
36 | [assembly: AssemblyFileVersion("0.2.0.0")]
37 |
--------------------------------------------------------------------------------
/LibOrbisPkg.Core.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29326.143
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibOrbisPkg.Core", "LibOrbisPkg.Core\LibOrbisPkg.Core.csproj", "{DA387D16-5ADB-4D8E-8B6C-B53BA6DCEF78}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PkgTool.Core", "PkgTool.Core\PkgTool.Core.csproj", "{296B3186-3C4A-490B-B33F-76BF62953020}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {DA387D16-5ADB-4D8E-8B6C-B53BA6DCEF78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {DA387D16-5ADB-4D8E-8B6C-B53BA6DCEF78}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {DA387D16-5ADB-4D8E-8B6C-B53BA6DCEF78}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {DA387D16-5ADB-4D8E-8B6C-B53BA6DCEF78}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {296B3186-3C4A-490B-B33F-76BF62953020}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {296B3186-3C4A-490B-B33F-76BF62953020}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {296B3186-3C4A-490B-B33F-76BF62953020}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {296B3186-3C4A-490B-B33F-76BF62953020}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {C8FE18B1-9D06-4955-95C8-430BD68892DB}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/PkgEditor/Views/View.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Windows.Forms;
6 |
7 | namespace PkgEditor.Views
8 | {
9 | public class View : UserControl
10 | {
11 | ///
12 | /// A reference to the main window owning this view control.
13 | ///
14 | public MainWin mainWin;
15 |
16 | ///
17 | /// The Main window should subscribe to this event to get notified when the document is modified.
18 | ///
19 | public event EventHandler SaveStatusChanged;
20 |
21 | ///
22 | /// This method should be called by an overloading class when the document has been modified, so the UI can update the Save/As buttons.
23 | ///
24 | protected void OnSaveStatusChanged() => SaveStatusChanged?.Invoke(this, new EventArgs());
25 |
26 | ///
27 | /// This should return true if the current document can be File->saved with Ctrl-S.
28 | ///
29 | public virtual bool CanSave { get; }
30 |
31 | ///
32 | /// This should return true if the current document can be File->save-as'd with Ctrl-Shift-S.
33 | ///
34 | public virtual bool CanSaveAs { get; }
35 |
36 | ///
37 | /// This method is called when the user presses Ctrl-S or clicks File->Save
38 | ///
39 | public virtual void Save() { }
40 |
41 | ///
42 | /// This method is called when the user presses Ctrl-Shift-S or clicks File->Save As...
43 | ///
44 | public virtual void SaveAs() { }
45 |
46 | ///
47 | /// This method is called when the user presse Ctrl-W or clicks File->Close
48 | ///
49 | public virtual void Close() { }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/LibOrbisPkg/PFS/PFSCWriter.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using LibOrbisPkg.Util;
3 |
4 | namespace LibOrbisPkg.PFS
5 | {
6 | ///
7 | /// Writes a PFSC header to to a stream. Doesn't actually do compression or anything interesting.
8 | ///
9 | class PFSCWriter
10 | {
11 | const int BlockSize = 0x10000;
12 | /*
13 | * PFSC Header
14 | * NUM_BLOCKS = CEIL(size / BLOCK_SZ)
15 | * 0x000 : PFSC Magic (4 bytes)
16 | * 0x004 : Unknown (8 bytes)
17 | * 0x00C : Block Size (4 bytes)
18 | * 0x010 : Block Size (8 bytes)
19 | * 0x018 : Block offsets pointer (4 bytes)
20 | * 0x020 : Data start (8 bytes)
21 | * 0x028 : Data length (8 bytes)
22 | * 0x400 : Blocks (8 bytes * NUM_BLOCKS)
23 | * 0x10000 : Data (variable)
24 | */
25 | private long num_blocks;
26 | public PFSCWriter(long size)
27 | {
28 | num_blocks = (size + BlockSize - 1) / BlockSize;
29 | var pointer_table_size = 8 + num_blocks * 8;
30 | var additional_pointer_blocks = ((pointer_table_size - 0xFC00) + 0xFFFF) / 0x10000;
31 | HeaderSize = 0x10000 + (additional_pointer_blocks > 0 ? BlockSize * additional_pointer_blocks : 0);
32 | }
33 |
34 | public readonly long HeaderSize;
35 | public void WritePFSCHeader(Stream s)
36 | {
37 | var start = s.Position;
38 | s.WriteInt32BE(0x50465343); // 'PFSC'
39 | s.WriteLE(0);
40 | s.WriteLE(6);
41 | s.WriteLE(BlockSize);
42 | s.WriteLE((long)BlockSize);
43 | s.WriteLE(0x400L);
44 | s.WriteLE(HeaderSize);
45 | s.WriteLE(num_blocks * BlockSize);
46 | s.Position = start + 0x400L;
47 | for(long i = 0; i <= num_blocks; i++)
48 | {
49 | s.WriteLE(HeaderSize + (i * BlockSize));
50 | }
51 | s.Position = start + HeaderSize;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/PkgEditor/Views/PFSView.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace PkgEditor.Views
2 | {
3 | partial class PFSView
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, 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 Component Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.fileView1 = new PkgEditor.Views.FileView();
32 | this.SuspendLayout();
33 | //
34 | // fileView1
35 | //
36 | this.fileView1.Dock = System.Windows.Forms.DockStyle.Fill;
37 | this.fileView1.Location = new System.Drawing.Point(0, 0);
38 | this.fileView1.Name = "fileView1";
39 | this.fileView1.Size = new System.Drawing.Size(557, 354);
40 | this.fileView1.TabIndex = 0;
41 | //
42 | // PFSView
43 | //
44 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
45 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
46 | this.Controls.Add(this.fileView1);
47 | this.Name = "PFSView";
48 | this.Size = new System.Drawing.Size(557, 354);
49 | this.ResumeLayout(false);
50 |
51 | }
52 |
53 | #endregion
54 |
55 | private FileView fileView1;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/LibOrbisPkg/PlayGo/Manifest.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using System.Xml.Serialization;
3 |
4 | namespace LibOrbisPkg.PlayGo
5 | {
6 | [XmlRoot(ElementName = "psproject")]
7 | class Manifest
8 | {
9 | [XmlAttribute("fmt")]
10 | public string Format;
11 | [XmlAttribute("version")]
12 | public string version;
13 | [XmlElement(ElementName = "chunk_info")]
14 | public GP4.ChunkInfo chunk_info;
15 |
16 |
17 | public static void WriteTo(Manifest proj, System.IO.Stream s)
18 | {
19 | XmlSerializer mySerializer = new XmlSerializer(typeof(Manifest));
20 | mySerializer.Serialize(s, proj);
21 | }
22 |
23 | public static Manifest ReadFrom(System.IO.Stream s)
24 | {
25 | XmlSerializer mySerializer = new XmlSerializer(typeof(Manifest));
26 | var proj = (Manifest)mySerializer.Deserialize(s);
27 | return proj;
28 | }
29 |
30 | public static Manifest FromProject(GP4.Gp4Project project)
31 | {
32 | var man = new Manifest
33 | {
34 | Format = "playgo-manifest",
35 | version = "0990",
36 | chunk_info = project.volume.chunk_info
37 | };
38 | man.chunk_info.chunks = null;
39 | return man;
40 | }
41 |
42 | public static byte[] Default =
43 | ("\r\n" +
44 | "\r\n" +
45 | " \r\n" +
46 | " \r\n" +
47 | " \r\n" +
48 | " 0\r\n" +
49 | " \r\n" +
50 | " \r\n" +
51 | " \r\n" +
52 | "\r\n").Select(x => (byte)x).ToArray();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/PkgEditor/Views/ObjectView.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace PkgEditor.Views
2 | {
3 | partial class ObjectView
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, 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 Component Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.treeView1 = new System.Windows.Forms.TreeView();
32 | this.SuspendLayout();
33 | //
34 | // treeView1
35 | //
36 | this.treeView1.Dock = System.Windows.Forms.DockStyle.Fill;
37 | this.treeView1.Location = new System.Drawing.Point(0, 0);
38 | this.treeView1.Name = "treeView1";
39 | this.treeView1.Size = new System.Drawing.Size(150, 150);
40 | this.treeView1.TabIndex = 0;
41 | //
42 | // ObjectView
43 | //
44 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
45 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
46 | this.Controls.Add(this.treeView1);
47 | this.Name = "ObjectView";
48 | this.ResumeLayout(false);
49 |
50 | }
51 |
52 | #endregion
53 |
54 | private System.Windows.Forms.TreeView treeView1;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/PkgEditor/LogWindow.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace PkgEditor
2 | {
3 | partial class LogWindow
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, 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 Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.logBox = new System.Windows.Forms.TextBox();
32 | this.SuspendLayout();
33 | //
34 | // logBox
35 | //
36 | this.logBox.Dock = System.Windows.Forms.DockStyle.Fill;
37 | this.logBox.Location = new System.Drawing.Point(0, 0);
38 | this.logBox.Multiline = true;
39 | this.logBox.Name = "logBox";
40 | this.logBox.ReadOnly = true;
41 | this.logBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
42 | this.logBox.Size = new System.Drawing.Size(575, 257);
43 | this.logBox.TabIndex = 0;
44 | //
45 | // LogWindow
46 | //
47 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
48 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
49 | this.ClientSize = new System.Drawing.Size(575, 257);
50 | this.Controls.Add(this.logBox);
51 | this.Name = "LogWindow";
52 | this.ShowIcon = false;
53 | this.Text = "LogWindow";
54 | this.ResumeLayout(false);
55 | this.PerformLayout();
56 |
57 | }
58 |
59 | #endregion
60 |
61 | public System.Windows.Forms.TextBox logBox;
62 | }
63 | }
--------------------------------------------------------------------------------
/PlaygoChunkDat.bt:
--------------------------------------------------------------------------------
1 | LittleEndian();
2 |
3 | char magic[4];
4 | uint16 version_major;
5 | uint16 version_minor;
6 | uint16 image_count;
7 | uint16 chunk_count;
8 | uint16 mchunk_count;
9 | uint16 scenario_count;
10 | uint32 file_size;
11 | uint16 default_scenario_id;
12 | uint16 attrib;
13 | uint32 sdk_ver;
14 | uint16 disc_count;
15 | uint16 layer_bmp;
16 | char reserved[32];
17 | char content_id[48];
18 |
19 | FSeek(0xC0);
20 | uint32 chunk_attrs_offset;
21 | uint32 chunk_attrs_size;
22 |
23 | uint32 chunk_mchunks_offset;
24 | uint32 chunk_mchunks_size;
25 |
26 | uint32 chunk_labels_offset;
27 | uint32 chunk_labels_size;
28 |
29 | uint32 mchunk_attrs_offset;
30 | uint32 mchunk_attrs_size;
31 |
32 | uint32 scenario_attrs_offset;
33 | uint32 scenario_attrs_size;
34 |
35 | uint32 scenario_chunks_offset;
36 | uint32 scenario_chunks_size;
37 |
38 | uint32 scenario_labels_offset;
39 | uint32 scenario_labels_size;
40 |
41 | uint32 inner_mchunk_attrs_offset;
42 | uint32 inner_mchunk_attrs_size;
43 |
44 | FSeek(chunk_attrs_offset);
45 | struct {
46 | byte flag;
47 | byte image_disc_layer_no;
48 | byte req_locus;
49 | FSeek(FTell() + 0xB);
50 | uint16 mchunk_count;
51 | uint64 language_mask;
52 | uint32 mchunks_offset;
53 | uint32 label_offset;
54 | } chunk_attrs[chunk_count];
55 | FSeek(chunk_mchunks_offset);
56 | uint16 chunk_mchunks[chunk_mchunks_size/2];
57 | FSeek(chunk_labels_offset);
58 | char chunk_labels[chunk_labels_size];
59 |
60 | typedef struct {
61 | uint64 offset;
62 | uint64 size;
63 | } mchunk_attr;
64 |
65 | FSeek(mchunk_attrs_offset);
66 | mchunk_attr mchunk_attrs[mchunk_count];
67 |
68 | FSeek(inner_mchunk_attrs_offset);
69 | mchunk_attr inner_mchunk_attrs[mchunk_count];
70 |
71 |
72 | FSeek(scenario_attrs_offset);
73 | struct {
74 | byte type;
75 | FSeek(0x13 + FTell());
76 | uint16 initial_chunk_count;
77 | uint16 chunk_count;
78 | uint32 chunks_offset;
79 | uint32 label_offset;
80 | } scenario_attrs[scenario_count];
81 |
82 | FSeek(scenario_chunks_offset);
83 | uint16 scenario_chunks[scenario_chunks_size/2];
84 |
85 | FSeek(scenario_labels_offset);
86 | char scenario_labels[scenario_labels_size];
--------------------------------------------------------------------------------
/PkgEditor/Views/PFSView.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Drawing;
5 | using System.Data;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 | using LibOrbisPkg.PFS;
11 | using LibOrbisPkg.Util;
12 | using System.IO.MemoryMappedFiles;
13 |
14 | namespace PkgEditor.Views
15 | {
16 | public partial class PFSView : View
17 | {
18 | private MemoryMappedFile pfsFile;
19 | private MemoryMappedViewAccessor va;
20 | private PfsReader reader;
21 | public PFSView(string filename)
22 | {
23 | InitializeComponent();
24 | pfsFile = MemoryMappedFile.CreateFromFile(filename, System.IO.FileMode.Open, mapName: null, 0, MemoryMappedFileAccess.Read);
25 | va = pfsFile.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read);
26 | va.Read(0, out int val);
27 | if (val == PFSCReader.Magic)
28 | reader = new PfsReader(new PFSCReader(va));
29 | else
30 | {
31 | PfsHeader header;
32 | using (var h = pfsFile.CreateViewStream(0, 0x600, MemoryMappedFileAccess.Read))
33 | {
34 | header = PfsHeader.ReadFromStream(h);
35 | }
36 | byte[] tweak = null, data = null;
37 | if (header.Mode.HasFlag(PfsMode.Encrypted))
38 | {
39 | var passcode = new PasscodeEntry("Please enter data key", 32);
40 | passcode.Text = "PFS is encrypted";
41 | passcode.ShowDialog();
42 | data = passcode.Passcode.FromHexCompact();
43 |
44 | passcode = new PasscodeEntry("Please enter tweak key", 32);
45 | passcode.Text = "PFS is encrypted";
46 | passcode.ShowDialog();
47 | data = passcode.Passcode.FromHexCompact();
48 | reader = new PfsReader(va, data: data, tweak: tweak);
49 | }
50 | else
51 | {
52 | reader = new PfsReader(va);
53 | }
54 | }
55 | fileView1.AddRoot(reader, filename);
56 | }
57 |
58 | public override void Close()
59 | {
60 | va.Dispose();
61 | pfsFile.Dispose();
62 | base.Close();
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/LibOrbisPkg/Util/OffsetStream.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace LibOrbisPkg.Util
4 | {
5 | ///
6 | /// A stream that acts as a window to another stream at the given offset.
7 | /// Seek operations will be relative to the offset. Size operations will
8 | /// pretend any part of the stream previous doesn't exist.
9 | ///
10 | public class OffsetStream : Stream
11 | {
12 | ///
13 | /// Creates an offset stream. Does not own the parent stream.
14 | ///
15 | ///
16 | ///
17 | public OffsetStream(Stream s, long offset)
18 | {
19 | src = s;
20 | if(src.Length < offset)
21 | {
22 | src.SetLength(offset);
23 | }
24 | this.offset = offset;
25 | }
26 | private Stream src;
27 | private long offset;
28 |
29 | public override bool CanRead => src.CanRead;
30 |
31 | public override bool CanSeek => src.CanSeek;
32 |
33 | public override bool CanWrite => src.CanWrite;
34 |
35 | public override long Length => src.Length - offset;
36 |
37 | public override long Position { get => src.Position - offset; set => src.Position = value + offset; }
38 |
39 | public override void Flush() => src.Flush();
40 |
41 | public override int Read(byte[] buffer, int offset, int count)
42 | {
43 | return src.Read(buffer, offset, count);
44 | }
45 |
46 | public override long Seek(long where, SeekOrigin origin)
47 | {
48 | switch (origin)
49 | {
50 | case SeekOrigin.Begin:
51 | src.Seek(where + offset, origin);
52 | break;
53 | case SeekOrigin.Current:
54 | src.Seek(where, origin);
55 | break;
56 | case SeekOrigin.End:
57 | src.Seek(where, origin);
58 | break;
59 | default:
60 | break;
61 | }
62 | return Position;
63 | }
64 |
65 | public override void SetLength(long value)
66 | {
67 | src.SetLength(value + offset);
68 | }
69 |
70 | public override void Write(byte[] buffer, int offset, int count)
71 | {
72 | src.Write(buffer, offset, count);
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/LibOrbisPkg.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.4.33213.308
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibOrbisPkg", "LibOrbisPkg\LibOrbisPkg.csproj", "{B053F491-FF0F-4CBB-B03B-520591BB0441}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PkgEditor", "PkgEditor\PkgEditor.csproj", "{60B5D407-D849-4B84-8A5E-D740EA1F8125}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | Release-minimal|Any CPU = Release-minimal|Any CPU
15 | EndGlobalSection
16 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
17 | {B053F491-FF0F-4CBB-B03B-520591BB0441}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
18 | {B053F491-FF0F-4CBB-B03B-520591BB0441}.Debug|Any CPU.Build.0 = Debug|Any CPU
19 | {B053F491-FF0F-4CBB-B03B-520591BB0441}.Release|Any CPU.ActiveCfg = Release|Any CPU
20 | {B053F491-FF0F-4CBB-B03B-520591BB0441}.Release|Any CPU.Build.0 = Release|Any CPU
21 | {B053F491-FF0F-4CBB-B03B-520591BB0441}.Release-minimal|Any CPU.ActiveCfg = Release|Any CPU
22 | {B053F491-FF0F-4CBB-B03B-520591BB0441}.Release-minimal|Any CPU.Build.0 = Release|Any CPU
23 | {60B5D407-D849-4B84-8A5E-D740EA1F8125}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24 | {60B5D407-D849-4B84-8A5E-D740EA1F8125}.Debug|Any CPU.Build.0 = Debug|Any CPU
25 | {60B5D407-D849-4B84-8A5E-D740EA1F8125}.Release|Any CPU.ActiveCfg = Release|Any CPU
26 | {60B5D407-D849-4B84-8A5E-D740EA1F8125}.Release|Any CPU.Build.0 = Release|Any CPU
27 | {60B5D407-D849-4B84-8A5E-D740EA1F8125}.Release-minimal|Any CPU.ActiveCfg = Release|Any CPU
28 | {60B5D407-D849-4B84-8A5E-D740EA1F8125}.Release-minimal|Any CPU.Build.0 = Release|Any CPU
29 | EndGlobalSection
30 | GlobalSection(SolutionProperties) = preSolution
31 | HideSolutionNode = FALSE
32 | EndGlobalSection
33 | GlobalSection(ExtensibilityGlobals) = postSolution
34 | SolutionGuid = {37BE3247-7A80-4D43-B59B-008F49D5CCE3}
35 | EndGlobalSection
36 | GlobalSection(Performance) = preSolution
37 | HasPerformanceSessions = true
38 | EndGlobalSection
39 | EndGlobal
40 |
--------------------------------------------------------------------------------
/LibOrbisPkg/Util/ReaderBase.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace LibOrbisPkg.Util
5 | {
6 | public class ReaderBase
7 | {
8 | [StructLayout(LayoutKind.Explicit, Size = 8)]
9 | private unsafe struct storage
10 | {
11 | [FieldOffset(0)]
12 | public byte u8;
13 | [FieldOffset(0)]
14 | public sbyte s8;
15 | [FieldOffset(0)]
16 | public ushort u16;
17 | [FieldOffset(0)]
18 | public short s16;
19 | [FieldOffset(0)]
20 | public uint u32;
21 | [FieldOffset(0)]
22 | public int s32;
23 | [FieldOffset(0)]
24 | public ulong u64;
25 | [FieldOffset(0)]
26 | public long s64;
27 | [FieldOffset(0)]
28 | public float f32;
29 | [FieldOffset(0)]
30 | public double f64;
31 | [FieldOffset(0)]
32 | public fixed byte buf[8];
33 | }
34 |
35 | private storage buffer;
36 | protected Stream s;
37 | protected bool flipEndian;
38 | protected ReaderBase(bool flipEndian, Stream stream)
39 | {
40 | s = stream;
41 | this.flipEndian = flipEndian;
42 | }
43 | private ref storage ReadEndian(int count)
44 | {
45 | unsafe
46 | {
47 | if (flipEndian)
48 | for (int i = count - 1 ; i >= 0; i--) buffer.buf[i] = (byte)s.ReadByte();
49 | else
50 | for (int i = 0; i < count; i++) buffer.buf[i] = (byte)s.ReadByte();
51 | }
52 | return ref buffer;
53 | }
54 | protected byte Byte() => ReadEndian(1).u8;
55 | protected sbyte SByte() => ReadEndian(1).s8;
56 | protected ushort UShort() => ReadEndian(2).u16;
57 | protected short Short() => ReadEndian(2).s16;
58 | protected uint UInt() => ReadEndian(4).u32;
59 | protected int Int() => ReadEndian(4).s32;
60 | protected ulong ULong() => ReadEndian(8).u64;
61 | protected long Long() => ReadEndian(8).s64;
62 | //protected unsafe void ReadBytes(byte* arr, int count)
63 | //{
64 | // for (var i = 0; i < count; i++)
65 | // {
66 | // arr[i] = (byte)s.ReadByte();
67 | // }
68 | //}
69 | protected byte[] ReadBytes(int count)
70 | {
71 | var ret = new byte[count];
72 | s.Read(ret, 0, count);
73 | return ret;
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/LibOrbisPkg/Util/SubStream.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace LibOrbisPkg.Util
5 | {
6 | public class SubStream : Stream
7 | {
8 | public override bool CanRead => true;
9 |
10 | public override bool CanSeek => true;
11 |
12 | public override bool CanWrite => false;
13 |
14 | public override long Length { get; }
15 |
16 | public override long Position
17 | {
18 | get
19 | {
20 | return position;
21 | }
22 |
23 | set
24 | {
25 | Seek(value, SeekOrigin.Begin);
26 | }
27 | }
28 |
29 | ///
30 | /// Creates a non-owning read-only window into a stream
31 | ///
32 | public SubStream(Stream s, long offset, long length)
33 | {
34 | this.parent = s;
35 | this.offset = offset;
36 | Length = length;
37 | }
38 |
39 | private Stream parent;
40 | private long offset;
41 | private long position;
42 |
43 | public override int Read(byte[] buffer, int offset, int count)
44 | {
45 | parent.Seek(this.offset + Position, SeekOrigin.Begin);
46 | if (count + Position > Length)
47 | {
48 | count = (int)(Length - Position);
49 | }
50 | int bytes_read = parent.Read(buffer, offset, count);
51 | position += bytes_read;
52 | return bytes_read;
53 | }
54 |
55 | public override long Seek(long offset, SeekOrigin origin)
56 | {
57 | switch (origin)
58 | {
59 | case SeekOrigin.Begin:
60 | break;
61 | case SeekOrigin.Current:
62 | offset += position;
63 | break;
64 | case SeekOrigin.End:
65 | offset += Length;
66 | break;
67 | }
68 | if (offset > Length)
69 | {
70 | offset = Length;
71 | }
72 | else if (offset < 0)
73 | {
74 | offset = 0;
75 | }
76 | position = offset;
77 | return position;
78 | }
79 |
80 | #region Not Supported
81 | public override void Flush()
82 | {
83 | throw new NotSupportedException();
84 | }
85 | public override void SetLength(long value)
86 | {
87 | throw new NotSupportedException();
88 | }
89 |
90 | public override void Write(byte[] buffer, int offset, int count)
91 | {
92 | throw new NotSupportedException();
93 | }
94 | #endregion
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/PkgEditor/ValidationDialog.cs:
--------------------------------------------------------------------------------
1 | using LibOrbisPkg.GP4;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.ComponentModel;
5 | using System.Data;
6 | using System.Drawing;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 | using System.Windows.Forms;
11 |
12 | namespace PkgEditor
13 | {
14 | public partial class ValidationDialog : Form
15 | {
16 | public ValidationDialog(List results = null)
17 | {
18 | InitializeComponent();
19 | if (results != null)
20 | {
21 | fatalLabel.Visible = false;
22 | foreach (var error in results)
23 | {
24 | validateListBox1.Items.Add(error);
25 | if (error.Type == ValidateResult.ResultType.Fatal)
26 | {
27 | ignoreButton.Enabled = false;
28 | fatalLabel.Visible = true;
29 | }
30 | }
31 | }
32 | }
33 |
34 | private void ignoreButton_Click(object sender, EventArgs e)
35 | {
36 | DialogResult = DialogResult.Ignore;
37 | Close();
38 | }
39 | }
40 |
41 | public class ValidateListBox : ListBox
42 | {
43 | public ValidateListBox()
44 | {
45 | DrawMode = DrawMode.OwnerDrawFixed;
46 | ItemHeight = 54;
47 | }
48 | protected override void OnDrawItem(DrawItemEventArgs e)
49 | {
50 | const TextFormatFlags flags = TextFormatFlags.Left | TextFormatFlags.Top | TextFormatFlags.WordBreak;
51 |
52 | e.DrawBackground();
53 | if (Items.Count > e.Index && Items[e.Index] is ValidateResult v)
54 | {
55 | var penColor = v.Type == ValidateResult.ResultType.Fatal ? Brushes.Red : Brushes.Yellow;
56 | e.Graphics.FillRectangle(penColor, 2, e.Bounds.Y + 2, width: ItemHeight / 2 - 4, height: ItemHeight - 4);
57 | var textRect = e.Bounds;
58 | textRect.X += ItemHeight / 2;
59 | textRect.Width -= ItemHeight / 2;
60 | textRect.Height = ItemHeight / 3;
61 | string itemText = v.Type.ToString();
62 | TextRenderer.DrawText(e.Graphics, itemText, new Font(e.Font, FontStyle.Bold), textRect, e.ForeColor, flags);
63 |
64 | textRect.Y += ItemHeight / 3;
65 | textRect.Height = 2 * ItemHeight / 3;
66 | itemText = DesignMode ? "Error Description" : v.Message;
67 | TextRenderer.DrawText(e.Graphics, itemText, e.Font, textRect, e.ForeColor, flags);
68 | }
69 |
70 | e.DrawFocusRectangle();
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/LibOrbisPkg/PKG/PkgProperties.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace LibOrbisPkg.PKG
4 | {
5 | ///
6 | /// Collection of data to use when building a PKG.
7 | ///
8 | public class PkgProperties
9 | {
10 | ///
11 | /// The volume type (should be one of the pkg_* types)
12 | ///
13 | public GP4.VolumeType VolumeType;
14 |
15 | ///
16 | /// 36 Character ID for the PKG
17 | ///
18 | public string ContentId;
19 |
20 | ///
21 | /// 32 Character Passcode
22 | ///
23 | public string Passcode;
24 |
25 | ///
26 | /// The volume timestamp.
27 | ///
28 | public DateTime TimeStamp;
29 |
30 | ///
31 | /// 32 Hex Character Entitlement Key (For AC, AL only)
32 | ///
33 | public string EntitlementKey;
34 |
35 | ///
36 | /// The creation date/time. Leave as default(DateTime) to disable
37 | ///
38 | public DateTime CreationDate;
39 |
40 | ///
41 | /// Set to true to use the creation time in addition to the date
42 | ///
43 | public bool UseCreationTime;
44 |
45 | ///
46 | /// The root of the directory tree for the PFS image.
47 | ///
48 | public PFS.FSDir RootDir;
49 |
50 | public static PkgProperties FromGp4(GP4.Gp4Project project, string projDir)
51 | {
52 | DateTime CreationDate;
53 | bool UseCreationTime = false;
54 | if ((project.volume.Package.CreationDate ?? "") == "")
55 | {
56 | CreationDate = default;
57 | }
58 | else if (project.volume.Package.CreationDate == "actual_datetime")
59 | {
60 | CreationDate = default;
61 | UseCreationTime = true;
62 | }
63 | else
64 | {
65 | var split = project.volume.Package.CreationDate.Split(' ');
66 | UseCreationTime = split.Length == 2; // Date and time specified
67 | CreationDate = DateTime.Parse(project.volume.Package.CreationDate).ToUniversalTime();
68 | }
69 | return new PkgProperties
70 | {
71 | ContentId = project.volume.Package.ContentId,
72 | VolumeType = project.volume.Type,
73 | Passcode = project.volume.Package.Passcode,
74 | TimeStamp = project.volume.TimeStamp,
75 | EntitlementKey = project.volume.Package.EntitlementKey,
76 | CreationDate = CreationDate,
77 | UseCreationTime = UseCreationTime,
78 | RootDir = PFS.PfsProperties.BuildFSTree(project, projDir)
79 | };
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/LibOrbisPkg/Util/WriterBase.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace LibOrbisPkg.Util
5 | {
6 | public class WriterBase
7 | {
8 | [StructLayout(LayoutKind.Explicit, Size = 8)]
9 | private unsafe struct storage
10 | {
11 | [FieldOffset(0)]
12 | public byte u8;
13 | [FieldOffset(0)]
14 | public sbyte s8;
15 | [FieldOffset(0)]
16 | public ushort u16;
17 | [FieldOffset(0)]
18 | public short s16;
19 | [FieldOffset(0)]
20 | public uint u32;
21 | [FieldOffset(0)]
22 | public int s32;
23 | [FieldOffset(0)]
24 | public ulong u64;
25 | [FieldOffset(0)]
26 | public long s64;
27 | [FieldOffset(0)]
28 | public float f32;
29 | [FieldOffset(0)]
30 | public double f64;
31 | [FieldOffset(0)]
32 | public fixed byte buf[8];
33 | }
34 |
35 | private storage buffer;
36 | protected Stream s;
37 | protected bool flipEndian;
38 | protected WriterBase(bool flipEndian, Stream stream)
39 | {
40 | s = stream;
41 | this.flipEndian = flipEndian;
42 | }
43 | private void WriteEndian(int count)
44 | {
45 | unsafe
46 | {
47 | if (flipEndian)
48 | for (int i = count - 1; i >= 0; i--) s.WriteByte(buffer.buf[i]);
49 | else
50 | for (int i = 0; i < count; i++) s.WriteByte(buffer.buf[i]);
51 | }
52 | }
53 | protected void Write(byte b) => s.WriteByte(b);
54 | protected void Write(sbyte sb) => Write((byte)sb);
55 | protected void Write(ushort u)
56 | {
57 | buffer.u16 = u;
58 | WriteEndian(2);
59 | }
60 | protected void Write(short u)
61 | {
62 | buffer.s16 = u;
63 | WriteEndian(2);
64 | }
65 | protected void Write(uint u)
66 | {
67 | buffer.u32 = u;
68 | WriteEndian(4);
69 | }
70 | protected void Write(int u)
71 | {
72 | buffer.s32 = u;
73 | WriteEndian(4);
74 | }
75 | protected void Write(ulong u)
76 | {
77 | buffer.u64 = u;
78 | WriteEndian(8);
79 | }
80 | protected void Write(long u)
81 | {
82 | buffer.s64 = u;
83 | WriteEndian(8);
84 | }
85 | protected void Write(byte[] b)
86 | {
87 | if (b == null)
88 | return;
89 | s.Write(b, 0, b.Length);
90 | }
91 | //protected unsafe void Write(byte* b, int count)
92 | //{
93 | // for (var i = 0; i < count; i++)
94 | // {
95 | // s.WriteByte(b[i]);
96 | // }
97 | //}
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/PkgEditor/KeyDB.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Runtime.Serialization;
6 | using System.Runtime.Serialization.Json;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace PkgEditor
11 | {
12 | ///
13 | /// Stores encryption keys in plain or hex-encoded strings.
14 | ///
15 | [DataContract]
16 | class KeyDB
17 | {
18 | [DataContract]
19 | public class XTSKey
20 | {
21 | [DataMember]
22 | public string Tweak { get; set; }
23 | [DataMember]
24 | public string Data { get; set; }
25 | }
26 | ///
27 | /// Plaintext passcodes indexed by Content ID
28 | ///
29 | [DataMember]
30 | public Dictionary Passcodes { get; set; }
31 | ///
32 | /// Compact hexadecimal encoded PFS encryption keys indexed by Content ID
33 | ///
34 | [DataMember]
35 | public Dictionary EKPFS { get; set; }
36 | ///
37 | /// Compact hexadecimal encoded XTS keys indexed by Content ID + first 4 bytes of PFS Image Digest
38 | ///
39 | [DataMember]
40 | public Dictionary XTS { get; set; }
41 |
42 | public void Save(string path = null)
43 | {
44 | if (path == null) path = FileName;
45 | using (var keydb = File.OpenWrite(path))
46 | {
47 | var serializer = new DataContractJsonSerializer(typeof(KeyDB), new DataContractJsonSerializerSettings()
48 | {
49 | UseSimpleDictionaryFormat = true,
50 | });
51 | serializer.WriteObject(keydb, this);
52 | }
53 | }
54 | private KeyDB() {
55 | Passcodes = new Dictionary();
56 | EKPFS = new Dictionary();
57 | XTS = new Dictionary();
58 | }
59 | private static KeyDB instance = null;
60 | public static KeyDB Instance { get => instance != null ? instance : (instance = Load()); }
61 | public static string FileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "LibOrbisPkg", "keydb.json");
62 | private static KeyDB Load()
63 | {
64 | if (!File.Exists(FileName))
65 | {
66 | Directory.CreateDirectory(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "LibOrbisPkg"));
67 | return new KeyDB();
68 | }
69 | using (var keydb = File.OpenRead(FileName))
70 | {
71 | var serializer = new DataContractJsonSerializer(typeof(KeyDB), new DataContractJsonSerializerSettings()
72 | {
73 | UseSimpleDictionaryFormat = true
74 | });
75 | return serializer.ReadObject(keydb) as KeyDB;
76 | }
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | # Declare files that will always have CRLF line endings on checkout.
7 | *.sln text eol=crlf
8 |
9 | ###############################################################################
10 | # Set default behavior for command prompt diff.
11 | #
12 | # This is need for earlier builds of msysgit that does not have it on by
13 | # default for csharp files.
14 | # Note: This is only used by command line
15 | ###############################################################################
16 | #*.cs diff=csharp
17 |
18 | ###############################################################################
19 | # Set the merge driver for project and solution files
20 | #
21 | # Merging from the command prompt will add diff markers to the files if there
22 | # are conflicts (Merging from VS is not affected by the settings below, in VS
23 | # the diff markers are never inserted). Diff markers may cause the following
24 | # file extensions to fail to load in VS. An alternative would be to treat
25 | # these files as binary and thus will always conflict and require user
26 | # intervention with every merge. To do so, just uncomment the entries below
27 | ###############################################################################
28 | #*.sln merge=binary
29 | #*.csproj merge=binary
30 | #*.vbproj merge=binary
31 | #*.vcxproj merge=binary
32 | #*.vcproj merge=binary
33 | #*.dbproj merge=binary
34 | #*.fsproj merge=binary
35 | #*.lsproj merge=binary
36 | #*.wixproj merge=binary
37 | #*.modelproj merge=binary
38 | #*.sqlproj merge=binary
39 | #*.wwaproj merge=binary
40 |
41 | ###############################################################################
42 | # behavior for image files
43 | #
44 | # image files are treated as binary by default.
45 | ###############################################################################
46 | #*.jpg binary
47 | #*.png binary
48 | #*.gif binary
49 |
50 | ###############################################################################
51 | # diff behavior for common document formats
52 | #
53 | # Convert binary document formats to text before diffing them. This feature
54 | # is only available from the command line. Turn it on by uncommenting the
55 | # entries below.
56 | ###############################################################################
57 | #*.doc diff=astextplain
58 | #*.DOC diff=astextplain
59 | #*.docx diff=astextplain
60 | #*.DOCX diff=astextplain
61 | #*.dot diff=astextplain
62 | #*.DOT diff=astextplain
63 | #*.pdf diff=astextplain
64 | #*.PDF diff=astextplain
65 | #*.rtf diff=astextplain
66 | #*.RTF diff=astextplain
67 |
--------------------------------------------------------------------------------
/PkgEditor/Properties/Resources.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 PkgEditor.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PkgEditor.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/LibOrbisPkg/Util/MersenneTwister.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace LibOrbisPkg.Util
4 | {
5 | ///
6 | /// Mersenne Twister PRNG
7 | ///
8 | public class MersenneTwister
9 | {
10 | public const int N = 624;
11 | const uint M = 397;
12 | const uint DefaultSeed = 0x12BD6AA;
13 | const uint MatrixA = 0x9908b0df;
14 | const uint UpperMask = 0x80000000;
15 | const uint LowerMask = 0x7fffffff;
16 | const uint Constant1 = 0x6C078965;
17 | const uint Constant2 = 0x19660D;
18 | const uint Constant3 = 0x5D588B65;
19 | const uint Constant4 = 0x9d2c5680;
20 | const uint Constant5 = 0xefc60000;
21 |
22 | public uint[] mt = new uint[N];
23 | uint Mask(int val) => ~((~0u) << val);
24 | uint TwoToThe(int val) => 1u << val;
25 |
26 | public MersenneTwister(uint seed = DefaultSeed)
27 | {
28 | mt[0] = seed;
29 | for (mti = 1; mti < N; mti++)
30 | {
31 | mt[mti] = mti + Constant1 * (mt[mti - 1] ^ (mt[mti - 1] >> 30));
32 | }
33 | }
34 |
35 | public MersenneTwister(uint[] seed) : this(DefaultSeed)
36 | {
37 | uint stateIdx = 1, seedIdx = 0;
38 | for (int length = Math.Max(N, seed.Length); length > 0; length--)
39 | {
40 | mt[stateIdx] = (mt[stateIdx] ^ ((mt[stateIdx - 1] ^ (mt[stateIdx - 1] >> 30)) * Constant2)) + seed[seedIdx] + seedIdx;
41 | stateIdx++;
42 | seedIdx++;
43 | if (stateIdx >= N) { mt[0] = mt[N - 1]; stateIdx = 1; }
44 | if (seedIdx >= seed.Length) seedIdx = 0;
45 | }
46 | for (int length = 0; length < N - 1; length++)
47 | {
48 | mt[stateIdx] = (mt[stateIdx] ^ ((mt[stateIdx - 1] ^ (mt[stateIdx - 1] >> 30)) * Constant3)) - stateIdx;
49 | stateIdx++;
50 | if (stateIdx >= N) { mt[0] = mt[N - 1]; stateIdx = 1; }
51 | }
52 | mt[0] = (1u << 31); /* MSB is 1; assuring non-zero initial array */
53 | }
54 |
55 | uint mti = 0;
56 | public uint Int32()
57 | {
58 | var mag01 = new uint[] { 0, MatrixA };
59 | uint y;
60 | if (mti >= N)
61 | {
62 | /* generate N words all at once */
63 | uint kk;
64 | for (kk = 0; kk < N - M; kk++)
65 | {
66 | y = (mt[kk] & UpperMask) | (mt[kk + 1] & LowerMask);
67 | mt[kk] = mt[kk + M] ^ ((y >> 1) & Mask(31)) ^ mag01[y & 1];
68 | }
69 | for (; kk < N - 1; kk++)
70 | {
71 | y = (mt[kk] & UpperMask) | (mt[kk + 1] & LowerMask);
72 | mt[kk] = mt[kk + M - N] ^ ((y >> 1) & Mask(31)) ^ mag01[y & 1];
73 | }
74 | y = (mt[N - 1] & UpperMask) | (mt[0] & LowerMask);
75 | mt[N - 1] = mt[M - 1] ^ ((y >> 1) & Mask(31)) ^ mag01[y & 1];
76 | mti = 0;
77 | }
78 |
79 | y = mt[mti++];
80 | /* Tempering */
81 | y ^= (y >> 11) & Mask(21);
82 | y ^= (y << 7) & Constant4;
83 | y ^= (y << 15) & Constant5;
84 | y ^= (y >> 18) & Mask(14);
85 | return y;
86 | }
87 |
88 | public uint Int31() => Int32() & Mask(31);
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/LibOrbisPkg/Util/XtsBlockTransform.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Security.Cryptography;
3 |
4 | namespace LibOrbisPkg.Util
5 | {
6 | public class XtsBlockTransform
7 | {
8 | // Used on the plaintext XORed with the encrypted sector number
9 | private SymmetricAlgorithm cipher;
10 | // Used to encrypt the tweak
11 | private SymmetricAlgorithm tweakCipher;
12 |
13 | private byte[] tweak = new byte[16];
14 | private byte[] xor = new byte[16];
15 | private byte[] xor2 = new byte[16];
16 | private byte[] encryptedTweak = new byte[16];
17 |
18 | ///
19 | /// Creates an AES-XTS-128 transformer
20 | ///
21 | public XtsBlockTransform(byte[] dataKey, byte[] tweakKey)
22 | {
23 | cipher = new AesManaged
24 | {
25 | Mode = CipherMode.ECB,
26 | KeySize = 128,
27 | Key = dataKey,
28 | Padding = PaddingMode.None,
29 | BlockSize = 128,
30 | };
31 | tweakCipher = new AesManaged
32 | {
33 | Mode = CipherMode.ECB,
34 | KeySize = 128,
35 | Key = tweakKey,
36 | Padding = PaddingMode.None,
37 | BlockSize = 128,
38 | };
39 | }
40 |
41 | public void EncryptSector(byte[] sector, ulong sectorNum) => CryptSector(sector, sectorNum, true);
42 | public void DecryptSector(byte[] sector, ulong sectorNum) => CryptSector(sector, sectorNum, false);
43 |
44 | ///
45 | /// Encrypts or decrypts the given sector with XEX.
46 | ///
47 | /// Sector plain/ciphertext
48 | /// Sector index number
49 | /// If this is set to true, encrypt the sector
50 | public void CryptSector(byte[] sector, ulong sectorNum, bool encrypt = false)
51 | {
52 | // Reset tweak to sector number
53 | Buffer.BlockCopy(BitConverter.GetBytes(sectorNum), 0, tweak, 0, 8);
54 | for (int x = 8; x < 16; x++)
55 | tweak[x] = 0;
56 | using (var tweakEncryptor = tweakCipher.CreateEncryptor())
57 | using (var cryptor = encrypt ? cipher.CreateEncryptor() : cipher.CreateDecryptor())
58 | {
59 | tweakEncryptor.TransformBlock(tweak, 0, 16, encryptedTweak, 0);
60 | for (int destOffset = 0; destOffset < sector.Length; destOffset += 16)
61 | {
62 | for (var x = 0; x < 16; x++)
63 | {
64 | xor[x] = (byte)(sector[x + destOffset] ^ encryptedTweak[x]);
65 | }
66 | cryptor.TransformBlock(xor, 0, 16, xor, 0);
67 | for (var x = 0; x < 16; x++)
68 | {
69 | sector[x + destOffset] = (byte)(xor[x] ^ encryptedTweak[x]);
70 | }
71 | // GF-Multiply Tweak
72 | int feedback = 0;
73 | for (int k = 0; k < 16; k++)
74 | {
75 | byte tmp = encryptedTweak[k];
76 | encryptedTweak[k] = (byte)(2 * encryptedTweak[k] | feedback);
77 | feedback = (tmp & 0x80) >> 7;
78 | }
79 | if (feedback != 0)
80 | encryptedTweak[0] ^= 0x87;
81 | }
82 | }
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/PkgEditor/Views/ObjectView.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Drawing;
5 | using System.Data;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Windows.Forms;
9 | using System.Collections;
10 |
11 | namespace PkgEditor.Views
12 | {
13 | public partial class ObjectView : View
14 | {
15 | public override bool CanSave => false;
16 | public override bool CanSaveAs => false;
17 |
18 | public ObjectView() : this(null) { }
19 | public ObjectView(object obj)
20 | {
21 | InitializeComponent();
22 | ObjectPreview(obj);
23 | }
24 |
25 | object previewObj;
26 | public void ObjectPreview(object obj)
27 | {
28 | treeView1.Nodes.Clear();
29 | AddObjectNodes(obj, treeView1.Nodes);
30 | previewObj = obj;
31 | }
32 |
33 | ///
34 | /// Adds the given object's public fields to the given TreeNodeCollection.
35 | ///
36 | void AddObjectNodes(object obj, TreeNodeCollection nodes)
37 | {
38 | if (obj == null) return;
39 | var fields = obj.GetType().GetFields();
40 | foreach (var f in fields)
41 | {
42 | if (f.IsLiteral) continue;
43 |
44 | var val = f.GetValue(obj);
45 | if (val is byte[] b)
46 | {
47 | nodes.Add(f.Name + " = " + LibOrbisPkg.Util.Crypto.AsHexCompact(b));
48 | }
49 | else if (f.FieldType.IsPrimitive || f.FieldType == typeof(string) || f.FieldType.IsEnum)
50 | {
51 | if (val != null)
52 | {
53 | nodes.Add(f.Name + " = " + val.ToString());
54 | }
55 | }
56 | else if (f.FieldType.IsArray)
57 | {
58 | AddArrayNodes(f.GetValue(obj) as Array, f.Name, nodes);
59 | }
60 | else if (f.FieldType.IsGenericType && f.FieldType.GetGenericTypeDefinition() == typeof(List<>))
61 | {
62 | var internalType = f.FieldType.GetGenericArguments()[0];
63 | AddArrayNodes((f.GetValue(obj) as IList).Cast