Add UMD Reader
This commit is contained in:
parent
50c91e024c
commit
9cb01e4a4b
|
@ -11,7 +11,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\PopsBuilder\PopsBuilder.csproj" />
|
||||
<ProjectReference Include="..\PopsBuilder\GameBuilder.csproj" />
|
||||
<ProjectReference Include="..\PspCrypto\PspCrypto.csproj" />
|
||||
<ProjectReference Include="..\PsvImage\PsvImage.csproj" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using CommunityToolkit.HighPerformance;
|
||||
using Ionic.Zlib;
|
||||
using PopsBuilder.Pops;
|
||||
using PopsBuilder.Psp;
|
||||
using GameBuilder.Pops;
|
||||
using GameBuilder.Psp;
|
||||
using PspCrypto;
|
||||
using PsvImage;
|
||||
using System;
|
||||
|
@ -11,6 +11,7 @@ using System.Linq;
|
|||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PbpResign
|
||||
{
|
||||
|
@ -1074,13 +1075,19 @@ namespace PbpResign
|
|||
|
||||
Console.WriteLine("VersionKey: " + BitConverter.ToString(NewVersionKey.ToArray()));
|
||||
|
||||
NpUmdImg npumd = new NpUmdImg(new NpDrmInfo(NewVersionKey.ToArray(), CId, npHdr.NpFlags),
|
||||
"fft.iso", "ULUS10297", File.ReadAllBytes("TEST\\PARAM.SFO"), true);
|
||||
UmdDisc disc = new UmdDisc("fft.iso");
|
||||
NpUmdImg npumd = new NpUmdImg(new NpDrmInfo(NewVersionKey.ToArray(), CId, npHdr.NpFlags), disc, false);
|
||||
|
||||
npumd.CreatePsar();
|
||||
byte[] paramFile = File.ReadAllBytes("TEST\\PARAM.SFO");
|
||||
|
||||
PbpBuilder.CreatePbp(paramFile, File.ReadAllBytes("TEST\\ICON0.PNG"), null, File.ReadAllBytes("TEST\\PIC0.PNG"), File.ReadAllBytes("TEST\\PIC1.PNG"), null, npumd, "FFT.PBP");
|
||||
PbpBuilder.CreatePbp(disc.DataFiles["PARAM.SFO"],
|
||||
disc.DataFiles["ICON0.PNG"],
|
||||
disc.DataFiles["ICON1.PMF"],
|
||||
disc.DataFiles["PIC0.PNG"],
|
||||
disc.DataFiles["PIC1.PNG"],
|
||||
disc.DataFiles["SND0.AT3"],
|
||||
npumd,
|
||||
"FFT.PBP");
|
||||
|
||||
return CopyNpUmdImg(input, output, pbpHdr, psarBuff, npHdr);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ using System.Threading.Channels;
|
|||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace PopsBuilder.Atrac3
|
||||
namespace GameBuilder.Atrac3
|
||||
{
|
||||
public class Atrac3ToolEncoder : IAtracEncoderBase
|
||||
{
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PopsBuilder.Atrac3
|
||||
namespace GameBuilder.Atrac3
|
||||
{
|
||||
public interface IAtracEncoderBase
|
||||
{
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PopsBuilder.Cue
|
||||
namespace GameBuilder.Cue
|
||||
{
|
||||
public class CueIndex
|
||||
{
|
||||
|
|
|
@ -5,7 +5,7 @@ using System.Linq.Expressions;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PopsBuilder.Cue
|
||||
namespace GameBuilder.Cue
|
||||
{
|
||||
public class CueReader : IDisposable
|
||||
{
|
||||
|
|
|
@ -5,7 +5,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PopsBuilder.Cue
|
||||
namespace GameBuilder.Cue
|
||||
{
|
||||
public class CueStream : Stream
|
||||
{
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PopsBuilder.Cue
|
||||
namespace GameBuilder.Cue
|
||||
{
|
||||
public class CueTrack
|
||||
{
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PopsBuilder.Cue
|
||||
namespace GameBuilder.Cue
|
||||
{
|
||||
public enum TrackType
|
||||
{
|
||||
|
|
|
@ -6,6 +6,11 @@
|
|||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DiscUtils.Core" Version="0.16.13" />
|
||||
<PackageReference Include="DiscUtils.Iso9660" Version="0.16.13" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\PspCrypto\PspCrypto.csproj" />
|
||||
</ItemGroup>
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GameBuilder
|
||||
{
|
||||
public static class MathUtil
|
||||
{
|
||||
public static int CalculateDifference(int val1, int val2)
|
||||
{
|
||||
int smaller = Convert.ToInt32(Math.Min(val1, val2));
|
||||
int larger = Convert.ToInt32(Math.Max(val1, val2));
|
||||
|
||||
return larger - smaller;
|
||||
}
|
||||
public static int CalculatePaddingAmount(int total, int alignTo)
|
||||
{
|
||||
int remainder = total % alignTo;
|
||||
int padAmt = alignTo - (remainder);
|
||||
if ((remainder) == 0) return 0;
|
||||
return padAmt;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
using PopsBuilder.Atrac3;
|
||||
using PopsBuilder.Cue;
|
||||
using PopsBuilder.Psp;
|
||||
using GameBuilder.Atrac3;
|
||||
using GameBuilder.Cue;
|
||||
using GameBuilder.Psp;
|
||||
using PspCrypto;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -9,7 +9,7 @@ using System.Runtime.InteropServices;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PopsBuilder.Pops
|
||||
namespace GameBuilder.Pops
|
||||
{
|
||||
public class DiscCompressor
|
||||
{
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PopsBuilder.Pops
|
||||
namespace GameBuilder.Pops
|
||||
{
|
||||
public class DiscInfo
|
||||
{
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
using PopsBuilder.Cue;
|
||||
using GameBuilder.Cue;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PopsBuilder.Pops
|
||||
namespace GameBuilder.Pops
|
||||
{
|
||||
public class EccRemoverStream : Stream
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using Org.BouncyCastle.Crypto.Paddings;
|
||||
using PopsBuilder.Psp;
|
||||
using GameBuilder;
|
||||
using GameBuilder.Psp;
|
||||
using PspCrypto;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -8,7 +8,7 @@ using System.Runtime.InteropServices;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PopsBuilder.Pops
|
||||
namespace GameBuilder.Pops
|
||||
{
|
||||
public class PopsImg : NpDrmPsar
|
||||
{
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
using Org.BouncyCastle.Crypto.Paddings;
|
||||
using PopsBuilder.Atrac3;
|
||||
using PopsBuilder.Cue;
|
||||
using PopsBuilder.Psp;
|
||||
using GameBuilder.Atrac3;
|
||||
using GameBuilder.Cue;
|
||||
using GameBuilder.Psp;
|
||||
using PspCrypto;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace PopsBuilder.Pops
|
||||
namespace GameBuilder.Pops
|
||||
{
|
||||
public class PsIsoImg : PopsImg
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using PopsBuilder.Atrac3;
|
||||
using PopsBuilder.Psp;
|
||||
using GameBuilder.Atrac3;
|
||||
using GameBuilder.Psp;
|
||||
using PspCrypto;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -8,7 +8,7 @@ using System.Runtime.InteropServices;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PopsBuilder.Pops
|
||||
namespace GameBuilder.Pops
|
||||
{
|
||||
public class PsTitleImg : PopsImg
|
||||
{
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PopsBuilder.Psp
|
||||
namespace GameBuilder.Psp
|
||||
{
|
||||
public class NpDrmInfo
|
||||
{
|
||||
|
|
|
@ -7,7 +7,7 @@ using System.Runtime.InteropServices;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PopsBuilder.Psp
|
||||
namespace GameBuilder.Psp
|
||||
{
|
||||
public abstract class NpDrmPsar : IDisposable
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using Org.BouncyCastle.Crypto.Paddings;
|
||||
using Org.BouncyCastle.Ocsp;
|
||||
using PopsBuilder.Pops;
|
||||
using GameBuilder.Pops;
|
||||
using PspCrypto;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PopsBuilder.Psp
|
||||
namespace GameBuilder.Psp
|
||||
{
|
||||
public class NpUmdImg : NpDrmPsar
|
||||
{
|
||||
|
@ -18,9 +18,8 @@ namespace PopsBuilder.Psp
|
|||
const int BLOCK_BASIS = 0x10;
|
||||
const int SECTOR_SZ = 2048;
|
||||
const int BLOCK_SZ = BLOCK_BASIS * SECTOR_SZ;
|
||||
public NpUmdImg(NpDrmInfo drmInfo, string iso, string discId, byte[] paramSfo, bool compress) : base(drmInfo)
|
||||
public NpUmdImg(NpDrmInfo drmInfo, UmdDisc umdImage, bool compress) : base(drmInfo)
|
||||
{
|
||||
this.isoStream = File.OpenRead(iso);
|
||||
this.compress = compress;
|
||||
|
||||
this.npHdr = new MemoryStream();
|
||||
|
@ -37,13 +36,18 @@ namespace PopsBuilder.Psp
|
|||
|
||||
this.headerKey = Rng.RandomBytes(0x10);
|
||||
|
||||
this.discId = discId.ToUpperInvariant().Replace("-", "").Replace("_", "");
|
||||
this.paramSfo = paramSfo;
|
||||
|
||||
isoBlocks = Convert.ToInt64((isoStream.Length + BLOCK_SZ - 1) / BLOCK_SZ);
|
||||
this.umdImage = umdImage;
|
||||
isoBlocks = Convert.ToInt64((umdImage.IsoStream.Length + BLOCK_SZ - 1) / BLOCK_SZ);
|
||||
|
||||
}
|
||||
|
||||
private void patchSfo()
|
||||
{
|
||||
Sfo sfoKeys = Sfo.ReadSfo(umdImage.DataFiles["PARAM.SFO"]);
|
||||
sfoKeys["DISC_ID"] = DrmInfo.ContentId.Substring(7, 9);
|
||||
umdImage.DataFiles["PARAM.SFO"] = sfoKeys.WriteSfo();
|
||||
|
||||
}
|
||||
private void createNpHdr()
|
||||
{
|
||||
npHdrUtil.WriteStr("NPUMDIMG");
|
||||
|
@ -69,6 +73,8 @@ namespace PopsBuilder.Psp
|
|||
|
||||
public void CreatePsar()
|
||||
{
|
||||
patchSfo();
|
||||
|
||||
createNpUmdTbl();
|
||||
byte[] tbl = encryptTable();
|
||||
this.dataKey = hashBlock(tbl);
|
||||
|
@ -102,7 +108,7 @@ namespace PopsBuilder.Psp
|
|||
using (MemoryStream dataPsp = new MemoryStream())
|
||||
{
|
||||
StreamUtil dataPspUtil = new StreamUtil(dataPsp);
|
||||
byte[] signature = signParamSfo(paramSfo);
|
||||
byte[] signature = signParamSfo(umdImage.DataFiles["PARAM.SFO"]);
|
||||
dataPspUtil.WriteBytes(signature);
|
||||
dataPspUtil.WritePadding(0x00, 0x530);
|
||||
dataPspUtil.WriteStrWithPadding(DrmInfo.ContentId, 0x00, 0x30);
|
||||
|
@ -118,14 +124,14 @@ namespace PopsBuilder.Psp
|
|||
private void createNpUmdTbl()
|
||||
{
|
||||
Int64 tableSz = isoBlocks * 0x20;
|
||||
Int64 isoSz = this.isoStream.Length;
|
||||
Int64 isoSz = umdImage.IsoStream.Length;
|
||||
int wsize = 0;
|
||||
Int64 isoOffset = 0x100 + tableSz;
|
||||
|
||||
for (int i = 0; i < isoBlocks; i++)
|
||||
{
|
||||
byte[] isoBuf = new byte[BLOCK_SZ];
|
||||
wsize = isoStream.Read(isoBuf, 0x00, BLOCK_SZ);
|
||||
wsize = umdImage.IsoStream.Read(isoBuf, 0x00, BLOCK_SZ);
|
||||
|
||||
byte[] wbuf = isoBuf;
|
||||
|
||||
|
@ -140,13 +146,14 @@ namespace PopsBuilder.Psp
|
|||
{
|
||||
wbuf = lzRcBuf;
|
||||
|
||||
wsize = (lzRcBuf.Length + 15) & ~15;
|
||||
wsize = lzRcBuf.Length;
|
||||
wsize += MathUtil.CalculatePaddingAmount(wsize, 16);
|
||||
Array.Resize(ref lzRcBuf, wsize);
|
||||
}
|
||||
}
|
||||
|
||||
int unpaddedSz = wsize;
|
||||
wsize = (wsize + 15) & ~15;
|
||||
wsize += MathUtil.CalculatePaddingAmount(wsize, 16);
|
||||
Array.Resize(ref wbuf, wsize);
|
||||
encryptBlock(wbuf, Convert.ToInt32(isoOffset));
|
||||
byte[] hash = hashBlock(wbuf);
|
||||
|
@ -162,7 +169,7 @@ namespace PopsBuilder.Psp
|
|||
|
||||
isoOffset += wsize;
|
||||
|
||||
Console.Write(Convert.ToInt32(Math.Floor((Convert.ToDouble(isoStream.Position) / Convert.ToDouble(isoStream.Length)) * 100.0)) + "%\r");
|
||||
Console.Write(Convert.ToInt32(Math.Floor((Convert.ToDouble(umdImage.IsoStream.Position) / Convert.ToDouble(umdImage.IsoStream.Length)) * 100.0)) + "%\r");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -215,7 +222,7 @@ namespace PopsBuilder.Psp
|
|||
{
|
||||
npHdrBodyUtil.WriteUInt16(SECTOR_SZ); // sector_sz
|
||||
|
||||
if (isoStream.Length > 0x40000000)
|
||||
if (umdImage.IsoStream.Length > 0x40000000)
|
||||
npHdrBodyUtil.WriteUInt16(0xE001); // unk_2
|
||||
else
|
||||
npHdrBodyUtil.WriteUInt16(0xE000); //unk_2
|
||||
|
@ -236,7 +243,7 @@ namespace PopsBuilder.Psp
|
|||
npHdrBodyUtil.WriteUInt32(0x01003FFE); // unk_40
|
||||
npHdrBodyUtil.WriteUInt32(0x100); // block_entry_offset
|
||||
|
||||
npHdrBodyUtil.WriteStrWithPadding(this.discId.Substring(0, 4) + "-" + this.discId.Substring(4, 5), 0x00, 0x10);
|
||||
npHdrBodyUtil.WriteStrWithPadding(umdImage.DiscIdSeperated, 0x00, 0x10);
|
||||
|
||||
npHdrBodyUtil.WriteInt32(0); // header_start_offset
|
||||
npHdrBodyUtil.WriteInt32(0); // unk_68
|
||||
|
@ -266,14 +273,11 @@ namespace PopsBuilder.Psp
|
|||
private Int64 isoBlocks;
|
||||
private bool compress;
|
||||
|
||||
private string discId;
|
||||
|
||||
private byte[] paramSfo;
|
||||
UmdDisc umdImage;
|
||||
|
||||
private byte[] headerKey;
|
||||
private byte[] dataKey;
|
||||
|
||||
private FileStream isoStream;
|
||||
|
||||
private MemoryStream npHdr;
|
||||
private StreamUtil npHdrUtil;
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PopsBuilder.Psp
|
||||
namespace GameBuilder.Psp
|
||||
{
|
||||
public static class PbpBuilder
|
||||
{
|
||||
|
@ -16,7 +16,9 @@ namespace PopsBuilder.Psp
|
|||
using (FileStream pbpStream = File.Open(outputFile, FileMode.Create))
|
||||
{
|
||||
byte[] dataPsp = dataPsar.GenerateDataPsp();
|
||||
int padLen = Convert.ToInt32(0x100 - (dataPsp.Length % 0x100));
|
||||
|
||||
int padLen = MathUtil.CalculatePaddingAmount(dataPsp.Length, 0x100);
|
||||
|
||||
Array.Resize(ref dataPsp, dataPsp.Length + padLen);
|
||||
|
||||
StreamUtil pbpUtil = new StreamUtil(pbpStream);
|
||||
|
|
|
@ -5,7 +5,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PopsBuilder.Psp
|
||||
namespace GameBuilder.Psp
|
||||
{
|
||||
public static class Rng
|
||||
{
|
||||
|
|
|
@ -0,0 +1,230 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Tracing;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// A Sfo Parser Written by SilicaAndPina
|
||||
// Because all the others are overly-complicated for no reason!
|
||||
// MIT Licensed.
|
||||
|
||||
namespace GameBuilder.Psp
|
||||
{
|
||||
|
||||
public class Sfo
|
||||
{
|
||||
|
||||
private struct SfoEntry
|
||||
{
|
||||
internal string keyName;
|
||||
internal byte type;
|
||||
internal UInt32 valueSize;
|
||||
internal UInt32 totalSize;
|
||||
internal byte align;
|
||||
internal object value;
|
||||
}
|
||||
|
||||
const int SFO_MAGIC = 0x46535000;
|
||||
const byte PSF_TYPE_BIN = 0;
|
||||
const byte PSF_TYPE_STR = 2;
|
||||
const byte PSF_TYPE_VAL = 4;
|
||||
|
||||
private Dictionary<string, SfoEntry> sfoEntries;
|
||||
public Object this[string index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return sfoEntries[index].value;
|
||||
}
|
||||
set
|
||||
{
|
||||
SfoEntry sfoEnt = sfoEntries[index];
|
||||
sfoEnt.value = value;
|
||||
|
||||
// update sz
|
||||
sfoEnt.valueSize = getObjectSz(sfoEnt.value);
|
||||
|
||||
if (sfoEnt.valueSize > sfoEnt.totalSize)
|
||||
sfoEnt.totalSize = Convert.ToUInt32(MathUtil.CalculatePaddingAmount(Convert.ToInt32(sfoEnt.valueSize), sfoEnt.align));
|
||||
|
||||
// update type
|
||||
sfoEnt.type = getPsfType(sfoEnt.value);
|
||||
|
||||
sfoEntries[index] = sfoEnt;
|
||||
}
|
||||
}
|
||||
public Sfo()
|
||||
{
|
||||
sfoEntries = new Dictionary<string, SfoEntry>();
|
||||
}
|
||||
|
||||
|
||||
private static UInt32 getObjectSz(Object obj)
|
||||
{
|
||||
if (obj is Int32) return 4;
|
||||
if (obj is UInt32) return 4;
|
||||
if (obj is String) return Convert.ToUInt32((obj as String).Length+1);
|
||||
if (obj is Byte[]) return Convert.ToUInt32((obj as Byte[]).Length);
|
||||
throw new Exception("Object is of unsupported type: " + obj.GetType());
|
||||
}
|
||||
|
||||
private static byte getPsfType(Object obj)
|
||||
{
|
||||
if (obj is Int32 || obj is UInt32) return PSF_TYPE_VAL;
|
||||
if (obj is String) return PSF_TYPE_STR;
|
||||
if (obj is Byte[]) return PSF_TYPE_BIN;
|
||||
throw new Exception("Object is of unsupported type: " + obj.GetType());
|
||||
}
|
||||
|
||||
public byte[] WriteSfo(UInt32 version = 0x101, Byte align = 0x4)
|
||||
{
|
||||
using (MemoryStream sfoStream = new MemoryStream())
|
||||
{
|
||||
WriteSfo(sfoStream, version, align);
|
||||
byte[] sfoBytes = sfoStream.ToArray();
|
||||
return sfoBytes;
|
||||
}
|
||||
}
|
||||
public void WriteSfo(Stream SfoStream, UInt32 version=0x101, Byte align=0x4)
|
||||
{
|
||||
using(MemoryStream sfoStream = new MemoryStream())
|
||||
{
|
||||
StreamUtil sfoUtil = new StreamUtil(sfoStream);
|
||||
|
||||
sfoUtil.WriteUInt32(SFO_MAGIC);
|
||||
sfoUtil.WriteUInt32(version);
|
||||
|
||||
sfoUtil.WriteUInt32(0xFFFFFFFF); // key offset
|
||||
sfoUtil.WriteUInt32(0xFFFFFFFF); // value offset
|
||||
// (will fill these in after the file is created)
|
||||
|
||||
sfoUtil.WriteInt32(sfoEntries.Count);
|
||||
|
||||
using (MemoryStream keyTable = new MemoryStream())
|
||||
{
|
||||
StreamUtil keyUtils = new StreamUtil(keyTable);
|
||||
using (MemoryStream valueTable = new MemoryStream())
|
||||
{
|
||||
StreamUtil valueUtils = new StreamUtil(valueTable);
|
||||
foreach (SfoEntry entry in sfoEntries.Values)
|
||||
{
|
||||
// write name
|
||||
sfoUtil.WriteUInt16(Convert.ToUInt16(keyTable.Position));
|
||||
keyUtils.WriteCStr(entry.keyName);
|
||||
|
||||
|
||||
|
||||
// write entry
|
||||
|
||||
sfoUtil.WriteByte(align); // align
|
||||
sfoUtil.WriteByte(entry.type); // type
|
||||
sfoUtil.WriteUInt32(entry.valueSize); // valueSize
|
||||
sfoUtil.WriteUInt32(entry.totalSize); // totalSize
|
||||
|
||||
// write data
|
||||
sfoUtil.WriteUInt32(Convert.ToUInt32(valueTable.Position)); // dataOffset
|
||||
|
||||
switch (entry.type)
|
||||
{
|
||||
case PSF_TYPE_VAL:
|
||||
valueUtils.WriteUInt32(Convert.ToUInt32(entry.value));
|
||||
valueUtils.WritePadding(0x00, Convert.ToInt32(entry.totalSize - entry.valueSize));
|
||||
break;
|
||||
case PSF_TYPE_STR:
|
||||
valueUtils.WriteStrWithPadding(entry.value as String, 0x00, Convert.ToInt32(entry.totalSize));
|
||||
break;
|
||||
case PSF_TYPE_BIN:
|
||||
valueUtils.WriteBytesWithPadding(entry.value as Byte[], 0x00, Convert.ToInt32(entry.totalSize));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
keyUtils.AlignTo(0x00, align);
|
||||
UInt32 keyOffset = Convert.ToUInt32(sfoStream.Position);
|
||||
keyTable.Seek(0x00, SeekOrigin.Begin);
|
||||
keyTable.CopyTo(sfoStream);
|
||||
|
||||
UInt32 valueOffset = Convert.ToUInt32(sfoStream.Position);
|
||||
valueTable.Seek(0x00, SeekOrigin.Begin);
|
||||
valueTable.CopyTo(sfoStream);
|
||||
|
||||
sfoStream.Seek(0x8, SeekOrigin.Begin);
|
||||
sfoUtil.WriteUInt32(keyOffset); // key offset
|
||||
sfoUtil.WriteUInt32(valueOffset); // value offset
|
||||
}
|
||||
}
|
||||
|
||||
sfoStream.Seek(0x0, SeekOrigin.Begin);
|
||||
sfoStream.CopyTo(SfoStream);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static Sfo ReadSfo(Stream SfoStream)
|
||||
{
|
||||
Sfo sfoFile = new Sfo();
|
||||
StreamUtil DataUtils = new StreamUtil(SfoStream);
|
||||
|
||||
// Read Sfo Header
|
||||
UInt32 magic = DataUtils.ReadUInt32();
|
||||
UInt32 version = DataUtils.ReadUInt32();
|
||||
UInt32 keyOffset = DataUtils.ReadUInt32();
|
||||
UInt32 valueOffset = DataUtils.ReadUInt32();
|
||||
UInt32 count = DataUtils.ReadUInt32();
|
||||
|
||||
if (magic == SFO_MAGIC) //\x00PSF
|
||||
{
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
SfoEntry entry = new SfoEntry();
|
||||
|
||||
UInt16 nameOffset = DataUtils.ReadUInt16();
|
||||
entry.align = DataUtils.ReadByte();
|
||||
entry.type = DataUtils.ReadByte();
|
||||
entry.valueSize = DataUtils.ReadUInt32();
|
||||
entry.totalSize = DataUtils.ReadUInt32();
|
||||
UInt32 dataOffset = DataUtils.ReadUInt32();
|
||||
|
||||
int keyLocation = Convert.ToInt32(keyOffset + nameOffset);
|
||||
entry.keyName = DataUtils.ReadStringAt(keyLocation);
|
||||
int valueLocation = Convert.ToInt32(valueOffset + dataOffset);
|
||||
|
||||
|
||||
switch (entry.type)
|
||||
{
|
||||
case PSF_TYPE_STR:
|
||||
entry.value = DataUtils.ReadStringAt(valueLocation);
|
||||
break;
|
||||
|
||||
case PSF_TYPE_VAL:
|
||||
entry.value = DataUtils.ReadUint32At(valueLocation);
|
||||
break;
|
||||
|
||||
case PSF_TYPE_BIN:
|
||||
entry.value = DataUtils.ReadBytesAt(valueLocation, Convert.ToInt32(entry.valueSize));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
sfoFile.sfoEntries[entry.keyName] = entry;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataException("Sfo Magic is Invalid.");
|
||||
}
|
||||
|
||||
return sfoFile;
|
||||
}
|
||||
|
||||
public static Sfo ReadSfo(byte[] Sfo)
|
||||
{
|
||||
using (MemoryStream SfoStream = new MemoryStream(Sfo))
|
||||
{
|
||||
return ReadSfo(SfoStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
using DiscUtils.Iso9660;
|
||||
using DiscUtils.Streams;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GameBuilder.Psp
|
||||
{
|
||||
public class UmdDisc : IDisposable
|
||||
{
|
||||
private string[] filesList = new string[]
|
||||
{
|
||||
"PSP_GAME\\ICON0.PNG",
|
||||
"PSP_GAME\\ICON1.PMF",
|
||||
"PSP_GAME\\PARAM.SFO",
|
||||
"PSP_GAME\\PIC0.PNG",
|
||||
"PSP_GAME\\PIC1.PNG",
|
||||
"PSP_GAME\\SND0.AT3"
|
||||
};
|
||||
|
||||
public Dictionary<string, byte[]?> DataFiles = new Dictionary<string, byte[]?>();
|
||||
public UmdDisc(string isoFile)
|
||||
{
|
||||
this.IsoFile = isoFile;
|
||||
this.IsoStream = File.OpenRead(isoFile);
|
||||
using (CDReader cdReader = new CDReader(this.IsoStream, true, true))
|
||||
{
|
||||
foreach (string file in filesList)
|
||||
{
|
||||
string fname = Path.GetFileName(file).ToUpperInvariant();
|
||||
if (cdReader.FileExists(file))
|
||||
{
|
||||
using (SparseStream s = cdReader.OpenFile(file, FileMode.Open))
|
||||
{
|
||||
byte[] data = new byte[s.Length];
|
||||
|
||||
s.Read(data, 0x00, data.Length);
|
||||
|
||||
DataFiles[fname] = data;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DataFiles[fname] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (DataFiles["PARAM.SFO"] is null) throw new Exception("ISO contains no PARAM.SFO file, so this is not a valid PSP game.");
|
||||
|
||||
Sfo sfo = Sfo.ReadSfo(DataFiles["PARAM.SFO"]);
|
||||
this.DiscId = sfo["DISC_ID"] as String;
|
||||
|
||||
IsoStream.Seek(0x00, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
|
||||
public string IsoFile;
|
||||
public FileStream IsoStream;
|
||||
public string DiscId;
|
||||
public string DiscIdSeperated
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.DiscId.Substring(0, 4) + "-" + this.DiscId.Substring(4, 5);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
IsoStream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@
|
|||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace PopsBuilder {
|
||||
namespace GameBuilder {
|
||||
using System;
|
||||
|
||||
|
||||
|
@ -39,7 +39,7 @@ namespace PopsBuilder {
|
|||
public static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PopsBuilder.Resources", typeof(Resources).Assembly);
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GameBuilder.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
|
|
|
@ -5,7 +5,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PopsBuilder
|
||||
namespace GameBuilder
|
||||
{
|
||||
public class StreamUtil
|
||||
{
|
||||
|
@ -14,21 +14,50 @@ namespace PopsBuilder
|
|||
{
|
||||
this.s = s;
|
||||
}
|
||||
|
||||
public void WriteStrWithPadding(string str, byte b, int len)
|
||||
public string ReadString()
|
||||
{
|
||||
byte[] sdata = Encoding.UTF8.GetBytes(str);
|
||||
if (len < sdata.Length)
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
s.Write(sdata, 0, len);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteBytes(sdata);
|
||||
WritePadding(b, (len - sdata.Length));
|
||||
while (true)
|
||||
{
|
||||
byte c = (byte)s.ReadByte();
|
||||
if (c == 0)
|
||||
break;
|
||||
ms.WriteByte(c);
|
||||
}
|
||||
return Encoding.UTF8.GetString(ms.ToArray());
|
||||
}
|
||||
}
|
||||
public UInt32 ReadUint32At(int location)
|
||||
{
|
||||
long oldPos = s.Position;
|
||||
s.Seek(location, SeekOrigin.Begin);
|
||||
UInt32 outp = ReadUInt32();
|
||||
s.Seek(oldPos, SeekOrigin.Begin);
|
||||
return outp;
|
||||
}
|
||||
|
||||
public byte[] ReadBytesAt(int location, int length)
|
||||
{
|
||||
long oldPos = s.Position;
|
||||
s.Seek(location, SeekOrigin.Begin);
|
||||
byte[] work_buf = ReadBytes(length);
|
||||
s.Seek(oldPos, SeekOrigin.Begin);
|
||||
return work_buf;
|
||||
}
|
||||
|
||||
public string ReadStringAt(int location)
|
||||
{
|
||||
long oldPos = s.Position;
|
||||
s.Seek(location, SeekOrigin.Begin);
|
||||
string outp = ReadString();
|
||||
s.Seek(oldPos, SeekOrigin.Begin);
|
||||
return outp;
|
||||
}
|
||||
public byte ReadByte()
|
||||
{
|
||||
return (byte)s.ReadByte();
|
||||
}
|
||||
public byte[] ReadBytes(int len)
|
||||
{
|
||||
byte[] data = new byte[len];
|
||||
|
@ -55,6 +84,23 @@ namespace PopsBuilder
|
|||
byte[] vbytes = ReadBytes(0x4);
|
||||
return BitConverter.ToInt32(vbytes);
|
||||
}
|
||||
public void WriteBytesWithPadding(byte[] data, byte b, int len)
|
||||
{
|
||||
if (len < data.Length)
|
||||
{
|
||||
s.Write(data, 0, len);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteBytes(data);
|
||||
WritePadding(b, (len - data.Length));
|
||||
}
|
||||
}
|
||||
public void WriteStrWithPadding(string str, byte b, int len)
|
||||
{
|
||||
WriteBytesWithPadding(Encoding.UTF8.GetBytes(str), b, len);
|
||||
}
|
||||
public void WriteInt64(Int64 v)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(v));
|
||||
|
@ -80,6 +126,11 @@ namespace PopsBuilder
|
|||
{
|
||||
WriteBytes(BitConverter.GetBytes(v));
|
||||
}
|
||||
public void WriteCStr(string str)
|
||||
{
|
||||
WriteStr(str);
|
||||
WriteByte(0x00);
|
||||
}
|
||||
public void WriteStr(string str)
|
||||
{
|
||||
WriteBytes(Encoding.UTF8.GetBytes(str));
|
||||
|
@ -87,6 +138,7 @@ namespace PopsBuilder
|
|||
|
||||
public void WritePadding(byte b, int len)
|
||||
{
|
||||
if (len < 0) return;
|
||||
for(int i = 0; i < len; i++)
|
||||
{
|
||||
WriteByte(b);
|
||||
|
@ -95,7 +147,8 @@ namespace PopsBuilder
|
|||
|
||||
public void AlignTo(byte padByte, int align)
|
||||
{
|
||||
int padAmt = Convert.ToInt32(align - (s.Position % align));
|
||||
int padAmt = MathUtil.CalculatePaddingAmount(Convert.ToInt32(s.Position), align);
|
||||
|
||||
this.WritePadding(padByte, padAmt);
|
||||
}
|
||||
public void PadUntil(byte b, int len)
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PopsBuilder
|
||||
namespace GameBuilder
|
||||
{
|
||||
public class xXEccD3str0yerXx
|
||||
{
|
||||
|
@ -42,7 +42,7 @@ namespace PopsBuilder
|
|||
}
|
||||
|
||||
// extend ISO image to compress block sz
|
||||
int padLen = COMPRESS_BLOCK_SZ - (Convert.ToInt32(noEccIso.Length) % COMPRESS_BLOCK_SZ);
|
||||
int padLen = MathUtil.CalculatePaddingAmount(Convert.ToInt32(noEccIso.Length), COMPRESS_BLOCK_SZ);
|
||||
byte[] padding = new byte[padLen];
|
||||
noEccIso.Write(padding, 0x00, padding.Length);
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PbpResign", "PbpResign\PbpR
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PsvImage", "PsvImage\PsvImage.csproj", "{0F4A59D9-FF92-4B4F-BDC4-4BC473F9AA5C}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PopsBuilder", "PopsBuilder\PopsBuilder.csproj", "{D1DF66DB-52BE-489C-A292-525BC71F2BB2}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameBuilder", "PopsBuilder\GameBuilder.csproj", "{D1DF66DB-52BE-489C-A292-525BC71F2BB2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
|
Loading…
Reference in New Issue