Skip to content

Commit edd1818

Browse files
committedJul 13, 2018
Initial commit
0 parents  commit edd1818

20 files changed

+2975
-0
lines changed
 

‎.editorconfig

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[*]
2+
indent_style = space
3+
indent_size = 2
4+
end_of_line = crlf

‎.gitattributes

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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

‎.gitignore

+261
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
## Ignore Visual Studio temporary files, build results, and
2+
## files generated by popular Visual Studio add-ons.
3+
4+
# User-specific files
5+
*.suo
6+
*.user
7+
*.userosscache
8+
*.sln.docstates
9+
10+
# User-specific files (MonoDevelop/Xamarin Studio)
11+
*.userprefs
12+
13+
# Build results
14+
[Dd]ebug/
15+
[Dd]ebugPublic/
16+
[Rr]elease/
17+
[Rr]eleases/
18+
x64/
19+
x86/
20+
bld/
21+
[Bb]in/
22+
[Oo]bj/
23+
[Ll]og/
24+
25+
# Visual Studio 2015 cache/options directory
26+
.vs/
27+
# Uncomment if you have tasks that create the project's static files in wwwroot
28+
#wwwroot/
29+
30+
# MSTest test Results
31+
[Tt]est[Rr]esult*/
32+
[Bb]uild[Ll]og.*
33+
34+
# NUNIT
35+
*.VisualState.xml
36+
TestResult.xml
37+
38+
# Build Results of an ATL Project
39+
[Dd]ebugPS/
40+
[Rr]eleasePS/
41+
dlldata.c
42+
43+
# DNX
44+
project.lock.json
45+
project.fragment.lock.json
46+
artifacts/
47+
48+
*_i.c
49+
*_p.c
50+
*_i.h
51+
*.ilk
52+
*.meta
53+
*.obj
54+
*.pch
55+
*.pdb
56+
*.pgc
57+
*.pgd
58+
*.rsp
59+
*.sbr
60+
*.tlb
61+
*.tli
62+
*.tlh
63+
*.tmp
64+
*.tmp_proj
65+
*.log
66+
*.vspscc
67+
*.vssscc
68+
.builds
69+
*.pidb
70+
*.svclog
71+
*.scc
72+
73+
# Chutzpah Test files
74+
_Chutzpah*
75+
76+
# Visual C++ cache files
77+
ipch/
78+
*.aps
79+
*.ncb
80+
*.opendb
81+
*.opensdf
82+
*.sdf
83+
*.cachefile
84+
*.VC.db
85+
*.VC.VC.opendb
86+
87+
# Visual Studio profiler
88+
*.psess
89+
*.vsp
90+
*.vspx
91+
*.sap
92+
93+
# TFS 2012 Local Workspace
94+
$tf/
95+
96+
# Guidance Automation Toolkit
97+
*.gpState
98+
99+
# ReSharper is a .NET coding add-in
100+
_ReSharper*/
101+
*.[Rr]e[Ss]harper
102+
*.DotSettings.user
103+
104+
# JustCode is a .NET coding add-in
105+
.JustCode
106+
107+
# TeamCity is a build add-in
108+
_TeamCity*
109+
110+
# DotCover is a Code Coverage Tool
111+
*.dotCover
112+
113+
# NCrunch
114+
_NCrunch_*
115+
.*crunch*.local.xml
116+
nCrunchTemp_*
117+
118+
# MightyMoose
119+
*.mm.*
120+
AutoTest.Net/
121+
122+
# Web workbench (sass)
123+
.sass-cache/
124+
125+
# Installshield output folder
126+
[Ee]xpress/
127+
128+
# DocProject is a documentation generator add-in
129+
DocProject/buildhelp/
130+
DocProject/Help/*.HxT
131+
DocProject/Help/*.HxC
132+
DocProject/Help/*.hhc
133+
DocProject/Help/*.hhk
134+
DocProject/Help/*.hhp
135+
DocProject/Help/Html2
136+
DocProject/Help/html
137+
138+
# Click-Once directory
139+
publish/
140+
141+
# Publish Web Output
142+
*.[Pp]ublish.xml
143+
*.azurePubxml
144+
# TODO: Comment the next line if you want to checkin your web deploy settings
145+
# but database connection strings (with potential passwords) will be unencrypted
146+
#*.pubxml
147+
*.publishproj
148+
149+
# Microsoft Azure Web App publish settings. Comment the next line if you want to
150+
# checkin your Azure Web App publish settings, but sensitive information contained
151+
# in these scripts will be unencrypted
152+
PublishScripts/
153+
154+
# NuGet Packages
155+
*.nupkg
156+
# The packages folder can be ignored because of Package Restore
157+
**/packages/*
158+
# except build/, which is used as an MSBuild target.
159+
!**/packages/build/
160+
# Uncomment if necessary however generally it will be regenerated when needed
161+
#!**/packages/repositories.config
162+
# NuGet v3's project.json files produces more ignoreable files
163+
*.nuget.props
164+
*.nuget.targets
165+
166+
# Microsoft Azure Build Output
167+
csx/
168+
*.build.csdef
169+
170+
# Microsoft Azure Emulator
171+
ecf/
172+
rcf/
173+
174+
# Windows Store app package directories and files
175+
AppPackages/
176+
BundleArtifacts/
177+
Package.StoreAssociation.xml
178+
_pkginfo.txt
179+
180+
# Visual Studio cache files
181+
# files ending in .cache can be ignored
182+
*.[Cc]ache
183+
# but keep track of directories ending in .cache
184+
!*.[Cc]ache/
185+
186+
# Others
187+
ClientBin/
188+
~$*
189+
*~
190+
*.dbmdl
191+
*.dbproj.schemaview
192+
*.jfm
193+
*.pfx
194+
*.publishsettings
195+
node_modules/
196+
orleans.codegen.cs
197+
198+
# Since there are multiple workflows, uncomment next line to ignore bower_components
199+
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
200+
#bower_components/
201+
202+
# RIA/Silverlight projects
203+
Generated_Code/
204+
205+
# Backup & report files from converting an old project file
206+
# to a newer Visual Studio version. Backup files are not needed,
207+
# because we have git ;-)
208+
_UpgradeReport_Files/
209+
Backup*/
210+
UpgradeLog*.XML
211+
UpgradeLog*.htm
212+
213+
# SQL Server files
214+
*.mdf
215+
*.ldf
216+
217+
# Business Intelligence projects
218+
*.rdl.data
219+
*.bim.layout
220+
*.bim_*.settings
221+
222+
# Microsoft Fakes
223+
FakesAssemblies/
224+
225+
# GhostDoc plugin setting file
226+
*.GhostDoc.xml
227+
228+
# Node.js Tools for Visual Studio
229+
.ntvs_analysis.dat
230+
231+
# Visual Studio 6 build log
232+
*.plg
233+
234+
# Visual Studio 6 workspace options file
235+
*.opt
236+
237+
# Visual Studio LightSwitch build output
238+
**/*.HTMLClient/GeneratedArtifacts
239+
**/*.DesktopClient/GeneratedArtifacts
240+
**/*.DesktopClient/ModelManifest.xml
241+
**/*.Server/GeneratedArtifacts
242+
**/*.Server/ModelManifest.xml
243+
_Pvt_Extensions
244+
245+
# Paket dependency manager
246+
.paket/paket.exe
247+
paket-files/
248+
249+
# FAKE - F# Make
250+
.fake/
251+
252+
# JetBrains Rider
253+
.idea/
254+
*.sln.iml
255+
256+
# CodeRush
257+
.cr/
258+
259+
# Python Tools for Visual Studio (PTVS)
260+
__pycache__/
261+
*.pyc

‎LibOrbisPkg.sln

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 15
4+
VisualStudioVersion = 15.0.27703.2000
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+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{B053F491-FF0F-4CBB-B03B-520591BB0441}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{B053F491-FF0F-4CBB-B03B-520591BB0441}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{B053F491-FF0F-4CBB-B03B-520591BB0441}.Release|Any CPU.ActiveCfg = Release|Any CPU
17+
{B053F491-FF0F-4CBB-B03B-520591BB0441}.Release|Any CPU.Build.0 = Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
GlobalSection(ExtensibilityGlobals) = postSolution
23+
SolutionGuid = {37BE3247-7A80-4D43-B59B-008F49D5CCE3}
24+
EndGlobalSection
25+
EndGlobal

‎LibOrbisPkg/GP4/Gp4Project.cs

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Xml.Serialization;
6+
7+
namespace LibOrbisPkg.GP4
8+
{
9+
10+
[XmlRoot(ElementName = "psproject")]
11+
public class Gp4Project
12+
{
13+
[XmlAttribute("fmt")]
14+
public string Format;
15+
[XmlAttribute("version")]
16+
public int version;
17+
[XmlElement(ElementName = "volume")]
18+
public Volume volume;
19+
[XmlElement(ElementName = "files")]
20+
public Files files;
21+
[XmlElement(ElementName = "rootdir")]
22+
public Dir[] RootDir;
23+
24+
public static void WriteTo(Gp4Project proj, System.IO.Stream s)
25+
{
26+
XmlSerializer mySerializer = new XmlSerializer(typeof(Gp4Project));
27+
mySerializer.Serialize(s, proj);
28+
}
29+
30+
public static Gp4Project ReadFrom(System.IO.Stream s)
31+
{
32+
XmlSerializer mySerializer = new XmlSerializer(typeof(Gp4Project));
33+
return (Gp4Project)mySerializer.Deserialize(s);
34+
}
35+
}
36+
37+
public class Volume
38+
{
39+
[XmlElement(ElementName = "volume_type")]
40+
public VolumeType Type;
41+
[XmlElement(ElementName = "volume_id")]
42+
public string Id;
43+
[XmlElement(ElementName = "volume_ts")]
44+
public DateTime TimeStamp;
45+
[XmlElement(ElementName = "package")]
46+
public PackageInfo Package;
47+
}
48+
49+
public enum VolumeType
50+
{
51+
pkg_ps4_ac_data,
52+
}
53+
54+
public class PackageInfo
55+
{
56+
[XmlAttribute("content_id")]
57+
public string ContentId;
58+
[XmlAttribute("passcode")]
59+
public string Passcode;
60+
}
61+
62+
public class Files : List<File>
63+
{
64+
[XmlAttribute("img_no")]
65+
public int ImageNum;
66+
}
67+
68+
public class File
69+
{
70+
[XmlAttribute("targ_path")]
71+
public string TargetPath;
72+
[XmlAttribute("orig_path")]
73+
public string OrigPath;
74+
}
75+
76+
public class Dir : List<Dir>
77+
{
78+
[XmlAttribute("targ_name")]
79+
public string TargetName;
80+
}
81+
82+
}

‎LibOrbisPkg/GP4/Gp4Reader.cs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Text;
5+
6+
namespace LibOrbisPkg.GP4
7+
{
8+
class Gp4Reader
9+
{
10+
public Gp4Reader(Stream s)
11+
{
12+
13+
}
14+
}
15+
}

‎LibOrbisPkg/GP4/Gp4Writer.cs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Text;
5+
using System.Xml.Serialization;
6+
7+
namespace LibOrbisPkg.GP4
8+
{
9+
class Gp4Writer
10+
{
11+
private Stream s;
12+
public Gp4Writer(Stream s)
13+
{
14+
this.s = s;
15+
}
16+
17+
public void Write(Gp4Project proj)
18+
{
19+
XmlSerializer mySerializer = new XmlSerializer(typeof(Gp4Project));
20+
mySerializer.Serialize(s, proj);
21+
}
22+
}
23+
}

‎LibOrbisPkg/LibOrbisPkg.csproj

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4+
<PropertyGroup>
5+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7+
<ProjectGuid>{B053F491-FF0F-4CBB-B03B-520591BB0441}</ProjectGuid>
8+
<OutputType>Library</OutputType>
9+
<AppDesignerFolder>Properties</AppDesignerFolder>
10+
<RootNamespace>LibOrbisPkg</RootNamespace>
11+
<AssemblyName>LibOrbisPkg</AssemblyName>
12+
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
13+
<FileAlignment>512</FileAlignment>
14+
</PropertyGroup>
15+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
16+
<DebugSymbols>true</DebugSymbols>
17+
<DebugType>full</DebugType>
18+
<Optimize>false</Optimize>
19+
<OutputPath>bin\Debug\</OutputPath>
20+
<DefineConstants>DEBUG;TRACE</DefineConstants>
21+
<ErrorReport>prompt</ErrorReport>
22+
<WarningLevel>4</WarningLevel>
23+
<LangVersion>7.3</LangVersion>
24+
</PropertyGroup>
25+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
26+
<DebugType>pdbonly</DebugType>
27+
<Optimize>true</Optimize>
28+
<OutputPath>bin\Release\</OutputPath>
29+
<DefineConstants>TRACE</DefineConstants>
30+
<ErrorReport>prompt</ErrorReport>
31+
<WarningLevel>4</WarningLevel>
32+
</PropertyGroup>
33+
<ItemGroup>
34+
<Reference Include="System" />
35+
<Reference Include="System.Core" />
36+
<Reference Include="System.Xml.Linq" />
37+
<Reference Include="System.Data.DataSetExtensions" />
38+
<Reference Include="Microsoft.CSharp" />
39+
<Reference Include="System.Data" />
40+
<Reference Include="System.Xml" />
41+
</ItemGroup>
42+
<ItemGroup>
43+
<Compile Include="GP4\Gp4Project.cs" />
44+
<Compile Include="GP4\Gp4Reader.cs" />
45+
<Compile Include="GP4\Gp4Writer.cs" />
46+
<Compile Include="PFS\FlatPathTable.cs" />
47+
<Compile Include="PFS\FSTree.cs" />
48+
<Compile Include="PFS\PFSBuilder.cs" />
49+
<Compile Include="PFS\PfsProperties.cs" />
50+
<Compile Include="PFS\PfsStructs.cs" />
51+
<Compile Include="PKG\Pkg.cs" />
52+
<Compile Include="PKG\PkgReader.cs" />
53+
<Compile Include="PKG\PkgWriter.cs" />
54+
<Compile Include="Properties\AssemblyInfo.cs" />
55+
<Compile Include="Util\ReaderBase.cs" />
56+
<Compile Include="Util\StreamExtensions.cs" />
57+
<Compile Include="Util\WriterBase.cs" />
58+
</ItemGroup>
59+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
60+
</Project>

‎LibOrbisPkg/PFS/FSTree.cs

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
6+
namespace LibOrbisPkg.PFS
7+
{
8+
abstract class FSNode
9+
{
10+
public FSDir Parent = null;
11+
public string name;
12+
public PfsDinode32 ino;
13+
public virtual long Size { get; set; }
14+
15+
public string FullPath(string suffix = "")
16+
{
17+
if (Parent == null) return suffix;
18+
return Parent.FullPath("/" + name + suffix);
19+
}
20+
}
21+
22+
class FSDir : FSNode
23+
{
24+
public List<FSDir> Dirs = new List<FSDir>();
25+
public List<FSFile> Files = new List<FSFile>();
26+
27+
28+
public List<PfsDirent> Dirents = new List<PfsDirent>();
29+
30+
public override long Size
31+
{
32+
get { return Dirents.Sum(d => d.EntSize); }
33+
}
34+
35+
public List<FSNode> GetAllChildren()
36+
{
37+
var ret = new List<FSNode>(GetAllChildrenDirs());
38+
ret.AddRange(GetAllChildrenFiles());
39+
return ret;
40+
}
41+
42+
public List<FSDir> GetAllChildrenDirs()
43+
{
44+
var ret = new List<FSDir>(Dirs);
45+
foreach (var dir in Dirs)
46+
foreach (var child in dir.GetAllChildrenDirs())
47+
ret.Add(child);
48+
return ret;
49+
}
50+
51+
public List<FSFile> GetAllChildrenFiles()
52+
{
53+
var ret = new List<FSFile>(Files);
54+
foreach (var dir in GetAllChildrenDirs())
55+
foreach (var f in dir.Files)
56+
ret.Add(f);
57+
return ret;
58+
}
59+
}
60+
61+
class FSFile : FSNode
62+
{
63+
public string OrigFileName;
64+
}
65+
}

‎LibOrbisPkg/PFS/FlatPathTable.cs

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using LibOrbisPkg.Util;
5+
6+
namespace LibOrbisPkg.PFS
7+
{
8+
9+
class FlatPathTable
10+
{
11+
private SortedDictionary<uint, uint> hashMap;
12+
13+
public int Size => hashMap.Count * 8;
14+
15+
/// <summary>
16+
/// Construct a flat_path_table out of the given filesystem nodes.
17+
/// </summary>
18+
/// <param name="nodes"></param>
19+
public FlatPathTable(List<FSNode> nodes)
20+
{
21+
hashMap = new SortedDictionary<uint, uint>();
22+
foreach (var n in nodes)
23+
{
24+
var hash = HashFunction(n.FullPath());
25+
if (hashMap.ContainsKey(hash))
26+
Console.WriteLine("Warning: hash collisions not yet handled.");
27+
hashMap[hash] = n.ino.Number;
28+
}
29+
}
30+
31+
/// <summary>
32+
/// Write this file to the stream.
33+
/// </summary>
34+
/// <param name="s"></param>
35+
public void WriteToStream(Stream s)
36+
{
37+
foreach (var hash in hashMap.Keys)
38+
{
39+
s.WriteUInt32LE(hash);
40+
s.WriteUInt32LE(hashMap[hash]);
41+
}
42+
}
43+
44+
/// <summary>
45+
/// Hashes the given name for the table.
46+
/// </summary>
47+
/// <param name="name"></param>
48+
/// <returns></returns>
49+
private static uint HashFunction(string name)
50+
{
51+
uint hash = 0;
52+
foreach (var c in name)
53+
hash += char.ToUpper(c) + 31 * hash;
54+
return hash;
55+
}
56+
}
57+
}

‎LibOrbisPkg/PFS/PFSBuilder.cs

+307
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.ComponentModel;
4+
using System.ComponentModel.Design.Serialization;
5+
using System.IO;
6+
using System.Linq;
7+
8+
namespace LibOrbisPkg.PFS
9+
{
10+
/// <summary>
11+
/// Contains the functionality to construct a PFS disk image.
12+
/// </summary>
13+
public class PfsBuilder
14+
{
15+
static int CeilDiv(int a, int b) => a / b + (a % b == 0 ? 0 : 1);
16+
static long CeilDiv(long a, long b) => a / b + (a % b == 0 ? 0 : 1);
17+
18+
private PfsHeader hdr;
19+
private List<PfsDinode32> inodes;
20+
private List<List<PfsDirent>> dirents;
21+
private List<PfsDirent> super_root_dirents;
22+
23+
private PfsDinode32 super_root_ino, fpt_ino;
24+
25+
private FSDir root;
26+
27+
private List<FSDir> allDirs;
28+
private List<FSFile> allFiles;
29+
private List<FSNode> allNodes;
30+
31+
private FlatPathTable fpt;
32+
33+
/// <summary>
34+
/// Builds and saves a PFS image.
35+
/// </summary>
36+
/// <param name="p"></param>
37+
public void BuildPfs(PfsProperties p)
38+
{
39+
// TODO: Combine the superroot-specific stuff with the rest of the data block writing.
40+
// I think this is as simple as adding superroot and flat_path_table to allNodes
41+
42+
hdr = new PfsHeader { BlockSize = p.BlockSize };
43+
inodes = new List<PfsDinode32>();
44+
dirents = new List<List<PfsDirent>>();
45+
46+
Console.WriteLine("Setting up root structure...");
47+
SetupRootStructure();
48+
BuildFSTree(root, p.RootDirectory);
49+
allDirs = root.GetAllChildrenDirs();
50+
allFiles = root.GetAllChildrenFiles();
51+
allNodes = new List<FSNode>(allDirs);
52+
allNodes.AddRange(allFiles);
53+
54+
Console.WriteLine("Creating directory inodes ({0})...", allDirs.Count);
55+
addDirInodes();
56+
57+
Console.WriteLine("Creating file inodes ({0})...", allFiles.Count);
58+
addFileInodes();
59+
60+
Console.WriteLine("Creating flat_path_table...");
61+
fpt = new FlatPathTable(allNodes);
62+
63+
64+
Console.WriteLine("Calculating data block layout...");
65+
allNodes.Insert(0, root);
66+
CalculateDataBlockLayout();
67+
68+
Console.WriteLine("Writing image file...");
69+
hdr.Ndblock = allFiles.Sum((f) => CeilDiv(f.Size, hdr.BlockSize));
70+
using (var stream = File.Create(p.ImageFilename))
71+
{
72+
Console.WriteLine("Writing header...");
73+
hdr.WriteToStream(stream);
74+
Console.WriteLine("Writing inodes...");
75+
WriteInodes(stream);
76+
Console.WriteLine("Writing superroot dirents");
77+
WriteSuperrootDirents(stream);
78+
79+
Console.WriteLine("Writing flat_path_table");
80+
stream.Position = fpt_ino.db[0] * hdr.BlockSize;
81+
fpt.WriteToStream(stream);
82+
83+
Console.WriteLine("Writing data blocks...");
84+
for (var x = 0; x < allNodes.Count; x++)
85+
{
86+
var f = allNodes[x];
87+
stream.Position = f.ino.db[0] * hdr.BlockSize;
88+
WriteFSNode(stream, f);
89+
}
90+
}
91+
}
92+
93+
/// <summary>
94+
/// Adds inodes for each dir.
95+
/// </summary>
96+
void addDirInodes()
97+
{
98+
inodes.Add(root.ino);
99+
foreach (var dir in allDirs)
100+
{
101+
var ino = new PfsDinode32
102+
{
103+
Mode = InodeMode.dir | InodeMode.rwx,
104+
Number = (uint)inodes.Count,
105+
Blocks = 1,
106+
Size = 65536
107+
};
108+
dir.ino = ino;
109+
dir.Dirents.Add(new PfsDirent { Name = ".", InodeNumber = ino.Number, Type = 4 });
110+
dir.Dirents.Add(new PfsDirent { Name = "..", InodeNumber = dir.Parent.ino.Number, Type = 5 });
111+
dirents.Add(dir.Dirents);
112+
var dirent = new PfsDirent { Name = dir.name, InodeNumber = (uint)inodes.Count, Type = 3 };
113+
dir.Parent.Dirents.Add(dirent);
114+
dir.Parent.ino.Nlink++;
115+
inodes.Add(ino);
116+
}
117+
}
118+
119+
/// <summary>
120+
/// Adds inodes for each file.
121+
/// </summary>
122+
void addFileInodes()
123+
{
124+
foreach (var file in allFiles)
125+
{
126+
var ino = new PfsDinode32
127+
{
128+
Mode = InodeMode.file | InodeMode.rwx,
129+
Size = file.Size,
130+
SizeCompressed = file.Size,
131+
Number = (uint)inodes.Count,
132+
Blocks = (uint)CeilDiv(file.Size, hdr.BlockSize)
133+
};
134+
file.ino = ino;
135+
var dirent = new PfsDirent { Name = file.name, Type = 2, InodeNumber = (uint)inodes.Count };
136+
file.Parent.Dirents.Add(dirent);
137+
inodes.Add(ino);
138+
}
139+
}
140+
141+
long dirSizeToSize(long size) => CeilDiv(size, hdr.BlockSize) * hdr.BlockSize;
142+
143+
/// <summary>
144+
/// Sets the data blocks. Also updates header for total number of data blocks.
145+
/// </summary>
146+
void CalculateDataBlockLayout()
147+
{
148+
var inodesPerBlock = hdr.BlockSize / PfsDinode32.SizeOf;
149+
hdr.DinodeCount = inodes.Count;
150+
hdr.DinodeBlockCount = CeilDiv(inodes.Count, inodesPerBlock);
151+
super_root_ino.db[0] = (int)(hdr.DinodeBlockCount + 1);
152+
153+
// flat path table
154+
fpt_ino.db[0] = super_root_ino.db[0] + 1;
155+
fpt_ino.Size = fpt.Size;
156+
fpt_ino.SizeCompressed = fpt.Size;
157+
fpt_ino.Blocks = (uint)CeilDiv(fpt.Size, hdr.BlockSize);
158+
for (int i = 1; i < fpt_ino.Blocks && i < fpt_ino.db.Length; i++)
159+
fpt_ino.db[i] = -1;
160+
161+
// All fs entries.
162+
var currentBlock = fpt_ino.db[0] + fpt_ino.Blocks;
163+
hdr.Ndblock = 0;
164+
// Calculate length of all dirent blocks
165+
foreach (var n in allNodes)
166+
{
167+
var blocks = CeilDiv(n.Size, hdr.BlockSize);
168+
n.ino.db[0] = (int)currentBlock;
169+
n.ino.Blocks = (uint)blocks;
170+
n.ino.Size = n is FSDir ? dirSizeToSize(n.Size) : n.Size;
171+
n.ino.SizeCompressed = n.ino.Size;
172+
for (int i = 1; i < blocks && i < n.ino.db.Length; i++)
173+
{
174+
n.ino.db[i] = -1;
175+
}
176+
currentBlock += blocks;
177+
hdr.Ndblock += blocks;
178+
}
179+
}
180+
181+
/// <summary>
182+
/// Creates inodes and dirents for superroot, flat_path_table, and uroot.
183+
/// Also, creates the root node for the FS tree.
184+
/// </summary>
185+
void SetupRootStructure()
186+
{
187+
inodes.Add(super_root_ino = new PfsDinode32
188+
{
189+
Mode = InodeMode.dir | InodeMode.rx_only,
190+
Blocks = 1,
191+
Size = 65536,
192+
SizeCompressed = 65536,
193+
Nlink = 1,
194+
Number = 0,
195+
Flags = InodeFlags.@internal
196+
});
197+
inodes.Add(fpt_ino = new PfsDinode32
198+
{
199+
Mode = InodeMode.file | InodeMode.rwx,
200+
Blocks = 1,
201+
Number = 1,
202+
Flags = InodeFlags.@internal
203+
});
204+
var uroot_ino = new PfsDinode32 { Mode = InodeMode.dir | InodeMode.rwx, Number = 2, Size = 65536, SizeCompressed = 65536, Blocks = 1 };
205+
206+
super_root_dirents = new List<PfsDirent>
207+
{
208+
new PfsDirent { InodeNumber = 1, Name = "flat_path_table", Type = 2 },
209+
new PfsDirent { InodeNumber = 2, Name = "uroot", Type = 3 }
210+
};
211+
212+
root = new FSDir
213+
{
214+
name = "uroot",
215+
ino = uroot_ino,
216+
Dirents = new List<PfsDirent>
217+
{
218+
new PfsDirent { Name = ".", Type = 4, InodeNumber = 2 },
219+
new PfsDirent { Name = "..", Type = 5, InodeNumber = 2 }
220+
}
221+
};
222+
}
223+
224+
/// <summary>
225+
/// Takes a directory and a root node, and recursively makes a filesystem tree.
226+
/// </summary>
227+
/// <param name="root"></param>
228+
/// <param name="rootDir"></param>
229+
void BuildFSTree(FSDir root, string rootDir)
230+
{
231+
foreach (var d in Directory.EnumerateDirectories(rootDir))
232+
{
233+
FSDir dir;
234+
root.Dirs.Add(dir = new FSDir { name = Path.GetFileName(d), Parent = root });
235+
BuildFSTree(dir, d);
236+
}
237+
238+
foreach (var f in Directory.EnumerateFiles(rootDir))
239+
{
240+
root.Files.Add(new FSFile
241+
{
242+
Parent = root,
243+
name = Path.GetFileName(f),
244+
OrigFileName = f,
245+
Size = new FileInfo(f).Length
246+
});
247+
}
248+
}
249+
250+
/// <summary>
251+
/// Writes all the inodes to the image file.
252+
/// </summary>
253+
/// <param name="s"></param>
254+
void WriteInodes(Stream s)
255+
{
256+
s.Position = hdr.BlockSize;
257+
foreach (var di in inodes)
258+
{
259+
di.WriteToStream(s);
260+
if (s.Position % hdr.BlockSize > hdr.BlockSize - PfsDinode32.SizeOf)
261+
{
262+
s.Position += hdr.BlockSize - (s.Position % hdr.BlockSize);
263+
}
264+
}
265+
}
266+
267+
/// <summary>
268+
/// Writes the dirents for the superroot, which precede the flat_path_table.
269+
/// </summary>
270+
/// <param name="stream"></param>
271+
void WriteSuperrootDirents(Stream stream)
272+
{
273+
stream.Position = hdr.BlockSize * (hdr.DinodeBlockCount + 1);
274+
foreach (var d in super_root_dirents)
275+
{
276+
d.WriteToStream(stream);
277+
}
278+
}
279+
280+
/// <summary>
281+
/// Writes all the data blocks.
282+
/// </summary>
283+
/// <param name="s"></param>
284+
void WriteFSNode(Stream s, FSNode f)
285+
{
286+
if (f is FSDir)
287+
{
288+
var dir = (FSDir)f;
289+
var startBlock = f.ino.db[0];
290+
foreach (var d in dir.Dirents)
291+
{
292+
d.WriteToStream(s);
293+
if (s.Position % hdr.BlockSize > hdr.BlockSize - PfsDirent.MaxSize)
294+
{
295+
s.Position = (++startBlock * hdr.BlockSize);
296+
}
297+
}
298+
}
299+
else if (f is FSFile)
300+
{
301+
var file = (FSFile)f;
302+
using (var fileStream = File.OpenRead(file.OrigFileName))
303+
fileStream.CopyTo(s);
304+
}
305+
}
306+
}
307+
}

‎LibOrbisPkg/PFS/PfsProperties.cs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace LibOrbisPkg.PFS
2+
{
3+
public class PfsProperties
4+
{
5+
public string RootDirectory;
6+
public uint BlockSize;
7+
public string ImageFilename;
8+
}
9+
}

‎LibOrbisPkg/PFS/PfsStructs.cs

+276
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
using LibOrbisPkg.Util;
8+
9+
namespace LibOrbisPkg.PFS
10+
{
11+
public enum PfsMode : ushort
12+
{
13+
Decrypted = 0x8,
14+
CompressedAndEncrypted = 0xD,
15+
None = 0
16+
}
17+
public class PfsHeader
18+
{
19+
public long Version = 1; // 1
20+
public long Magic = 20130315; // 20130315 (march 15 2013???)
21+
public long Id = 0;
22+
public byte Fmode = 0;
23+
public byte Clean = 0;
24+
public byte ReadOnly = 0;
25+
public byte Rsv = 0;
26+
public ushort Mode = 0;
27+
public ushort Unk1 = 0;
28+
public uint BlockSize = 0x10000;
29+
public uint NBackup = 0;
30+
/// <summary>
31+
/// This is always 1 for some reason.
32+
/// </summary>
33+
public long NBlock = 1;
34+
public long DinodeCount = 0;
35+
public long Ndblock = 0;
36+
public long DinodeBlockCount = 0;
37+
public long SuperrootInode = 0;
38+
39+
public void WriteToStream(System.IO.Stream s)
40+
{
41+
s.WriteInt64LE(Version);
42+
s.WriteInt64LE(Magic);
43+
s.WriteInt64LE(Id);
44+
s.WriteByte(Fmode);
45+
s.WriteByte(Clean);
46+
s.WriteByte(ReadOnly);
47+
s.WriteByte(Rsv);
48+
s.WriteUInt16LE(Mode);
49+
s.WriteUInt16LE(Unk1);
50+
s.WriteUInt32LE(BlockSize);
51+
s.WriteUInt32LE(NBackup);
52+
s.WriteInt64LE(NBlock);
53+
s.WriteInt64LE(DinodeCount);
54+
s.WriteInt64LE(Ndblock);
55+
s.WriteInt64LE(DinodeBlockCount);
56+
s.WriteInt64LE(SuperrootInode);
57+
}
58+
59+
public static PfsHeader ReadFromStream(System.IO.Stream s)
60+
{
61+
return new PfsHeader
62+
{
63+
Version = s.ReadInt64LE(),
64+
Magic = s.ReadInt64LE(),
65+
Id = s.ReadInt64LE(),
66+
Fmode = s.ReadUInt8(),
67+
Clean = s.ReadUInt8(),
68+
ReadOnly = s.ReadUInt8(),
69+
Rsv = s.ReadUInt8(),
70+
Mode = s.ReadUInt16LE(),
71+
Unk1 = s.ReadUInt16LE(),
72+
BlockSize = s.ReadUInt32LE(),
73+
NBackup = s.ReadUInt32LE(),
74+
NBlock = s.ReadInt64LE(),
75+
DinodeCount = s.ReadInt64LE(),
76+
Ndblock = s.ReadInt64LE(),
77+
DinodeBlockCount = s.ReadInt64LE(),
78+
SuperrootInode = s.ReadInt64LE()
79+
};
80+
}
81+
}
82+
83+
[Flags]
84+
public enum InodeMode : ushort
85+
{
86+
o_read = 1,
87+
o_write = 2,
88+
o_execute = 4,
89+
g_read = 8,
90+
g_write = 16,
91+
g_execute = 32,
92+
u_read = 64,
93+
u_write = 128,
94+
u_execute = 256,
95+
dir = 16384,
96+
file = 32768,
97+
rx_only = 0x16D,
98+
rwx = 0x1FF
99+
}
100+
101+
[Flags]
102+
public enum InodeFlags : uint
103+
{
104+
compressed = 0x1,
105+
unk1 = 0x2,
106+
unk2 = 0x4,
107+
unk3 = 0x8,
108+
@readonly = 0x10,
109+
unk4 = 0x20,
110+
unk5 = 0x40,
111+
unk6 = 0x80,
112+
unk7 = 0x100,
113+
unk8 = 0x200,
114+
unk9 = 0x400,
115+
unk10 = 0x800,
116+
unk11 = 0x1000,
117+
unk12 = 0x2000,
118+
unk13 = 0x4000,
119+
unk14 = 0x8000,
120+
unk15 = 0x10000,
121+
@internal = 0x20000
122+
}
123+
124+
public class PfsDinode32
125+
{
126+
public PfsDinode32()
127+
{
128+
SetTime((long)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds);
129+
}
130+
131+
public const long SizeOf = 0xA8;
132+
public uint Number;
133+
134+
/// <summary>
135+
/// Default is 555 octal.
136+
/// </summary>
137+
public InodeMode Mode = (InodeMode)0x16D;
138+
139+
/// <summary>
140+
/// Number of links to this file in the filesystem.
141+
/// 1 for regular files, 1 + 1 for every subdirectory for dirs.
142+
/// </summary>
143+
public ushort Nlink;
144+
public InodeFlags Flags;
145+
public long Size;
146+
public long SizeCompressed;
147+
public long Time1_sec;
148+
public long Time2_sec;
149+
public long Time3_sec;
150+
public long Time4_sec;
151+
public uint Time1_nsec;
152+
public uint Time2_nsec;
153+
public uint Time3_nsec;
154+
public uint Time4_nsec;
155+
public uint Uid;
156+
public uint Gid;
157+
public ulong Unk1;
158+
public ulong Unk2;
159+
public uint Blocks;
160+
public int[] db = new int[12];
161+
public int[] ib = new int[5];
162+
163+
public PfsDinode32 SetTime(long time)
164+
{
165+
Time1_sec = time;
166+
Time2_sec = time;
167+
Time3_sec = time;
168+
Time4_sec = time;
169+
return this;
170+
}
171+
172+
public void WriteToStream(Stream s)
173+
{
174+
s.WriteLE((ushort)Mode);
175+
s.WriteLE(Nlink);
176+
s.WriteLE((uint)Flags);
177+
s.WriteLE(Size);
178+
s.WriteLE(SizeCompressed);
179+
s.WriteLE(Time1_sec);
180+
s.WriteLE(Time2_sec);
181+
s.WriteLE(Time3_sec);
182+
s.WriteLE(Time4_sec);
183+
s.WriteLE(Time1_nsec);
184+
s.WriteLE(Time2_nsec);
185+
s.WriteLE(Time3_nsec);
186+
s.WriteLE(Time4_nsec);
187+
s.WriteLE(Uid);
188+
s.WriteLE(Gid);
189+
s.WriteLE(Unk1);
190+
s.WriteLE(Unk2);
191+
s.WriteLE(Blocks);
192+
foreach (var x in db) s.WriteLE(x);
193+
foreach (var x in ib) s.WriteLE(x);
194+
}
195+
196+
public static PfsDinode32 ReadFromStream(Stream s)
197+
{
198+
var di = new PfsDinode32
199+
{
200+
Mode = (InodeMode)s.ReadUInt16LE(),
201+
Nlink = s.ReadUInt16LE(),
202+
Flags = (InodeFlags)s.ReadUInt32LE(),
203+
Size = s.ReadInt64LE(),
204+
SizeCompressed = s.ReadInt64LE(),
205+
Time1_sec = s.ReadInt64LE(),
206+
Time2_sec = s.ReadInt64LE(),
207+
Time3_sec = s.ReadInt64LE(),
208+
Time4_sec = s.ReadInt64LE(),
209+
Time1_nsec = s.ReadUInt32LE(),
210+
Time2_nsec = s.ReadUInt32LE(),
211+
Time3_nsec = s.ReadUInt32LE(),
212+
Time4_nsec = s.ReadUInt32LE(),
213+
Uid = s.ReadUInt32LE(),
214+
Gid = s.ReadUInt32LE(),
215+
Unk1 = s.ReadUInt64LE(),
216+
Unk2 = s.ReadUInt64LE(),
217+
Blocks = s.ReadUInt32LE()
218+
};
219+
for (var i = 0; i < 12; i++) di.db[i] = s.ReadInt32LE();
220+
for (var i = 0; i < 5; i++) di.ib[i] = s.ReadInt32LE();
221+
return di;
222+
}
223+
}
224+
225+
public class PfsDirent
226+
{
227+
public static int MaxSize = 280;
228+
229+
public uint InodeNumber;
230+
public int Type;
231+
public int NameLength;
232+
public int EntSize;
233+
234+
public string Name
235+
{
236+
get { return name; }
237+
set
238+
{
239+
name = value;
240+
NameLength = name.Length;
241+
EntSize = NameLength + 17;
242+
if (EntSize % 8 != 0)
243+
EntSize += 8 - (EntSize % 8);
244+
}
245+
}
246+
247+
private string name;
248+
249+
public void WriteToStream(Stream s)
250+
{
251+
var pos = s.Position;
252+
s.WriteLE(InodeNumber);
253+
s.WriteLE(Type);
254+
s.WriteLE(NameLength);
255+
s.WriteLE(EntSize);
256+
s.Write(Encoding.ASCII.GetBytes(Name), 0, NameLength);
257+
var remaining = (int)(EntSize - (s.Position - pos));
258+
s.Write(new byte[remaining], 0, remaining);
259+
}
260+
261+
public PfsDirent ReadFromStream(Stream s)
262+
{
263+
var pos = s.Position;
264+
var d = new PfsDirent
265+
{
266+
InodeNumber = s.ReadUInt32LE(),
267+
Type = s.ReadInt32LE(),
268+
NameLength = s.ReadInt32LE(),
269+
EntSize = s.ReadInt32LE(),
270+
name = s.ReadASCIINullTerminated(NameLength)
271+
};
272+
s.Position = pos + d.EntSize;
273+
return d;
274+
}
275+
}
276+
}

‎LibOrbisPkg/PKG/Pkg.cs

+880
Large diffs are not rendered by default.

‎LibOrbisPkg/PKG/PkgReader.cs

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace LibOrbisPkg.PKG
6+
{
7+
class PkgReader : Util.ReaderBase
8+
{
9+
public PkgReader(System.IO.Stream s) : base(true, s)
10+
{
11+
}
12+
13+
public Pkg.Header ReadHeader()
14+
{
15+
var hdr = new Pkg.Header();
16+
s.Position = 0x00;
17+
hdr.CNTMagic = ReadBytes(4);
18+
if (!hdr.CNTMagic.Equals(Pkg.Magic))
19+
throw new Exception("Invalid CNT header");
20+
s.Position = 0x04;
21+
hdr.flags = (PKGFlags)UInt();
22+
s.Position = 0x08;
23+
hdr.unk_0x08 = UInt();
24+
s.Position = 0x0C;
25+
hdr.unk_0x0C = UInt(); /* 0xF */
26+
s.Position = 0x10;
27+
hdr.entry_count = UInt();
28+
s.Position = 0x14;
29+
hdr.sc_entry_count = UShort();
30+
s.Position = 0x16;
31+
hdr.entry_count_2 = UShort(); /* same as entry_count */
32+
s.Position = 0x18;
33+
hdr.entry_table_offset = UInt();
34+
s.Position = 0x1C;
35+
hdr.main_ent_data_size = UInt();
36+
s.Position = 0x20;
37+
hdr.body_offset = ULong();
38+
s.Position = 0x28;
39+
hdr.body_size = ULong();
40+
s.Position = 0x40;
41+
hdr.content_id = ReadBytes(Pkg.Header.PKG_CONTENT_ID_SIZE); // Length = PKG_CONTENT_ID_SIZE
42+
s.Position = 0x70;
43+
hdr.drm_type = UInt();
44+
s.Position = 0x74;
45+
hdr.content_type = UInt();
46+
s.Position = 0x78;
47+
hdr.content_flags = (ContentFlags)UInt();
48+
s.Position = 0x7C;
49+
hdr.promote_size = UInt();
50+
s.Position = 0x80;
51+
hdr.version_date = UInt();
52+
s.Position = 0x84;
53+
hdr.version_hash = UInt();
54+
s.Position = 0x88;
55+
hdr.unk_0x88 = UInt(); /* for delta patches only? */
56+
s.Position = 0x8C;
57+
hdr.unk_0x8C = UInt(); /* for delta patches only? */
58+
s.Position = 0x90;
59+
hdr.unk_0x90 = UInt(); /* for delta patches only? */
60+
s.Position = 0x94;
61+
hdr.unk_0x94 = UInt(); /* for delta patches only? */
62+
s.Position = 0x98;
63+
hdr.iro_tag = UInt();
64+
s.Position = 0x9C;
65+
hdr.ekc_version = UInt(); /* drm type version */
66+
s.Position = 0x100;
67+
hdr.sc_entries1_hash = ReadBytes(Pkg.HASH_SIZE);
68+
s.Position = 0x120;
69+
hdr.sc_entries2_hash = ReadBytes(Pkg.HASH_SIZE);
70+
s.Position = 0x140;
71+
hdr.digest_table_hash = ReadBytes(Pkg.HASH_SIZE);
72+
s.Position = 0x160;
73+
hdr.body_digest = ReadBytes(Pkg.HASH_SIZE);
74+
75+
// TODO: i think these fields are actually members of element of container array
76+
s.Position = 0x400;
77+
hdr.unk_0x400 = UInt();
78+
s.Position = 0x404;
79+
hdr.pfs_image_count = UInt();
80+
s.Position = 0x408;
81+
hdr.pfs_flags = ULong();
82+
s.Position = 0x410;
83+
hdr.pfs_image_offset = ULong();
84+
s.Position = 0x418;
85+
hdr.pfs_image_size = ULong();
86+
s.Position = 0x420;
87+
hdr.mount_image_offset = ULong();
88+
s.Position = 0x428;
89+
hdr.mount_image_size = ULong();
90+
s.Position = 0x430;
91+
hdr.package_size = ULong();
92+
s.Position = 0x438;
93+
hdr.pfs_signed_size = UInt();
94+
s.Position = 0x43C;
95+
hdr.pfs_cache_size = UInt();
96+
s.Position = 0x440;
97+
hdr.pfs_image_digest = ReadBytes(Pkg.HASH_SIZE);
98+
s.Position = 0x460;
99+
hdr.pfs_signed_digest = ReadBytes(Pkg.HASH_SIZE);
100+
s.Position = 0x480;
101+
hdr.pfs_split_size_nth_0 = ULong();
102+
s.Position = 0x488;
103+
hdr.pfs_split_size_nth_1 = ULong();
104+
return hdr;
105+
}
106+
}
107+
}

‎LibOrbisPkg/PKG/PkgWriter.cs

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace LibOrbisPkg.PKG
6+
{
7+
class PkgWriter : Util.WriterBase
8+
{
9+
public PkgWriter(System.IO.Stream s) : base(true, s) { }
10+
public void WriteHeader(in Pkg.Header hdr)
11+
{
12+
s.Position = 0x00;
13+
Write(hdr.CNTMagic);
14+
s.Position = 0x04;
15+
Write((uint)hdr.flags);
16+
s.Position = 0x08;
17+
Write(hdr.unk_0x08);
18+
s.Position = 0x0C;
19+
Write(hdr.unk_0x0C); /* 0xF */
20+
s.Position = 0x10;
21+
Write(hdr.entry_count);
22+
s.Position = 0x14;
23+
Write(hdr.sc_entry_count);
24+
s.Position = 0x16;
25+
Write(hdr.entry_count_2); /* same as entry_count */
26+
s.Position = 0x18;
27+
Write(hdr.entry_table_offset);
28+
s.Position = 0x1C;
29+
Write(hdr.main_ent_data_size);
30+
s.Position = 0x20;
31+
Write(hdr.body_offset);
32+
s.Position = 0x28;
33+
Write(hdr.body_size);
34+
s.Position = 0x40;
35+
Write(hdr.content_id); // Length = PKG_CONTENT_ID_SIZE
36+
s.Position = 0x70;
37+
Write(hdr.drm_type);
38+
s.Position = 0x74;
39+
Write(hdr.content_type);
40+
s.Position = 0x78;
41+
Write((uint)hdr.content_flags);
42+
s.Position = 0x7C;
43+
Write(hdr.promote_size);
44+
s.Position = 0x80;
45+
Write(hdr.version_date);
46+
s.Position = 0x84;
47+
Write(hdr.version_hash);
48+
s.Position = 0x88;
49+
Write(hdr.unk_0x88); /* for delta patches only? */
50+
s.Position = 0x8C;
51+
Write(hdr.unk_0x8C); /* for delta patches only? */
52+
s.Position = 0x90;
53+
Write(hdr.unk_0x90); /* for delta patches only? */
54+
s.Position = 0x94;
55+
Write(hdr.unk_0x94); /* for delta patches only? */
56+
s.Position = 0x98;
57+
Write(hdr.iro_tag);
58+
s.Position = 0x9C;
59+
Write(hdr.ekc_version); /* drm type version */
60+
s.Position = 0x100;
61+
Write(hdr.sc_entries1_hash);
62+
s.Position = 0x120;
63+
Write(hdr.sc_entries2_hash);
64+
s.Position = 0x140;
65+
Write(hdr.digest_table_hash);
66+
s.Position = 0x160;
67+
Write(hdr.body_digest);
68+
69+
// TODO: i think these fields are actually members of element of container array
70+
s.Position = 0x400;
71+
Write(hdr.unk_0x400);
72+
s.Position = 0x404;
73+
Write(hdr.pfs_image_count);
74+
s.Position = 0x408;
75+
Write(hdr.pfs_flags);
76+
s.Position = 0x410;
77+
Write(hdr.pfs_image_offset);
78+
s.Position = 0x418;
79+
Write(hdr.pfs_image_size);
80+
s.Position = 0x420;
81+
Write(hdr.mount_image_offset);
82+
s.Position = 0x428;
83+
Write(hdr.mount_image_size);
84+
s.Position = 0x430;
85+
Write(hdr.package_size);
86+
s.Position = 0x438;
87+
Write(hdr.pfs_signed_size);
88+
s.Position = 0x43C;
89+
Write(hdr.pfs_cache_size);
90+
s.Position = 0x440;
91+
Write(hdr.pfs_image_digest);
92+
s.Position = 0x460;
93+
Write(hdr.pfs_signed_digest);
94+
s.Position = 0x480;
95+
Write(hdr.pfs_split_size_nth_0);
96+
s.Position = 0x488;
97+
Write(hdr.pfs_split_size_nth_1);
98+
}
99+
}
100+
}
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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")]
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("1.0.0.0")]
36+
[assembly: AssemblyFileVersion("1.0.0.0")]

‎LibOrbisPkg/Util/ReaderBase.cs

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
using System;
2+
using System.IO;
3+
using System.Runtime.InteropServices;
4+
5+
namespace LibOrbisPkg.Util
6+
{
7+
public class ReaderBase
8+
{
9+
[StructLayout(LayoutKind.Explicit, Size = 8)]
10+
private struct storage
11+
{
12+
[FieldOffset(0)]
13+
public byte u8;
14+
[FieldOffset(0)]
15+
public sbyte s8;
16+
[FieldOffset(0)]
17+
public ushort u16;
18+
[FieldOffset(0)]
19+
public short s16;
20+
[FieldOffset(0)]
21+
public uint u32;
22+
[FieldOffset(0)]
23+
public int s32;
24+
[FieldOffset(0)]
25+
public ulong u64;
26+
[FieldOffset(0)]
27+
public long s64;
28+
[FieldOffset(0)]
29+
public float f32;
30+
[FieldOffset(0)]
31+
public double f64;
32+
[FieldOffset(0)]
33+
public byte[] buf;
34+
}
35+
36+
private storage buffer;
37+
protected Stream s;
38+
protected bool flipEndian;
39+
protected ReaderBase(bool flipEndian, Stream stream)
40+
{
41+
s = stream;
42+
this.flipEndian = flipEndian;
43+
buffer.buf = new byte[8];
44+
}
45+
private ref storage ReadEndian(int count)
46+
{
47+
s.Read(buffer.buf, 0, count);
48+
if (flipEndian)
49+
Array.Reverse(buffer.buf, 0, count);
50+
return ref buffer;
51+
}
52+
protected byte Byte() => ReadEndian(1).u8;
53+
protected sbyte SByte() => ReadEndian(1).s8;
54+
protected ushort UShort() => ReadEndian(2).u16;
55+
protected short Short() => ReadEndian(2).s16;
56+
protected uint UInt() => ReadEndian(4).u32;
57+
protected int Int() => ReadEndian(4).s32;
58+
protected ulong ULong() => ReadEndian(8).u64;
59+
protected long Long() => ReadEndian(8).s64;
60+
//protected unsafe void ReadBytes(byte* arr, int count)
61+
//{
62+
// for (var i = 0; i < count; i++)
63+
// {
64+
// arr[i] = (byte)s.ReadByte();
65+
// }
66+
//}
67+
protected byte[] ReadBytes(int count)
68+
{
69+
var ret = new byte[count];
70+
s.Read(ret, 0, count);
71+
return ret;
72+
}
73+
}
74+
}

‎LibOrbisPkg/Util/StreamExtensions.cs

+433
Large diffs are not rendered by default.

‎LibOrbisPkg/Util/WriterBase.cs

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
using System;
2+
using System.IO;
3+
using System.Runtime.InteropServices;
4+
5+
namespace LibOrbisPkg.Util
6+
{
7+
public class WriterBase
8+
{
9+
[StructLayout(LayoutKind.Explicit, Size = 8)]
10+
private struct storage
11+
{
12+
[FieldOffset(0)]
13+
public byte u8;
14+
[FieldOffset(0)]
15+
public sbyte s8;
16+
[FieldOffset(0)]
17+
public ushort u16;
18+
[FieldOffset(0)]
19+
public short s16;
20+
[FieldOffset(0)]
21+
public uint u32;
22+
[FieldOffset(0)]
23+
public int s32;
24+
[FieldOffset(0)]
25+
public ulong u64;
26+
[FieldOffset(0)]
27+
public long s64;
28+
[FieldOffset(0)]
29+
public float f32;
30+
[FieldOffset(0)]
31+
public double f64;
32+
[FieldOffset(0)]
33+
public byte[] buf;
34+
}
35+
36+
private storage buffer;
37+
protected Stream s;
38+
protected bool flipEndian;
39+
protected WriterBase(bool flipEndian, Stream stream)
40+
{
41+
s = stream;
42+
this.flipEndian = flipEndian;
43+
buffer.buf = new byte[8];
44+
}
45+
private void WriteEndian(int count)
46+
{
47+
if (flipEndian)
48+
Array.Reverse(buffer.buf, 0, count);
49+
s.Write(buffer.buf, 0, count);
50+
}
51+
protected void Write(byte b) => s.WriteByte(b);
52+
protected void Write(sbyte sb) => Write((byte)sb);
53+
protected void Write(ushort u)
54+
{
55+
buffer.u16 = u;
56+
WriteEndian(2);
57+
}
58+
protected void Write(short u)
59+
{
60+
buffer.s16 = u;
61+
WriteEndian(2);
62+
}
63+
protected void Write(uint u)
64+
{
65+
buffer.u32 = u;
66+
WriteEndian(4);
67+
}
68+
protected void Write(int u)
69+
{
70+
buffer.s32 = u;
71+
WriteEndian(4);
72+
}
73+
protected void Write(ulong u)
74+
{
75+
buffer.u64 = u;
76+
WriteEndian(8);
77+
}
78+
protected void Write(long u)
79+
{
80+
buffer.s64 = u;
81+
WriteEndian(8);
82+
}
83+
protected void Write(byte[] b)
84+
{
85+
s.Write(b, 0, b.Length);
86+
}
87+
//protected unsafe void Write(byte* b, int count)
88+
//{
89+
// for (var i = 0; i < count; i++)
90+
// {
91+
// s.WriteByte(b[i]);
92+
// }
93+
//}
94+
}
95+
}

0 commit comments

Comments
 (0)
Please sign in to comment.