You've already forked sceWork
mirror of
https://github.com/lifebottle/sceWork.git
synced 2026-02-13 15:16:05 -08:00
483 lines
19 KiB
C#
483 lines
19 KiB
C#
using StreamFAdd;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace sceWork
|
|
{
|
|
internal class sceHeader
|
|
{
|
|
const int SECTION_COUNT = 6;
|
|
public uint offsetScript;
|
|
public uint offsetStrings;
|
|
public uint[] sectionOffsets;
|
|
public uint sectionItemCount = 0;
|
|
public List<sceStrings> fileStrings;
|
|
public List<int> lineNumberList;
|
|
public List<string> plainStringList;
|
|
public Dictionary<long, sceInstruction> instructions;
|
|
public List<long> instructionOffsets;
|
|
|
|
public sceHeader(StreamFunctionAdd sfa, bool parse = true)
|
|
{
|
|
if (sfa.ReadAnsiStringSize(8) != "TOD1RSCE")
|
|
{
|
|
throw new Exception("Error #1: Bad Magic");
|
|
}
|
|
offsetScript = sfa.ReadUInt32();
|
|
offsetStrings = sfa.ReadUInt32();
|
|
sfa.ReadUInt32();
|
|
uint frame = sfa.ReadUInt32();
|
|
uint entry = sfa.ReadUInt32();
|
|
for (int i = 0; i < SECTION_COUNT; i++)
|
|
{
|
|
sectionItemCount += sfa.ReadUInt16();
|
|
}
|
|
sectionItemCount += 2;
|
|
|
|
// Don't care about the per section counts
|
|
for (int i = 0; i < SECTION_COUNT; i++)
|
|
{
|
|
sfa.ReadUInt16();
|
|
}
|
|
|
|
sectionOffsets = new uint[sectionItemCount];
|
|
sectionOffsets[0] = frame;
|
|
sectionOffsets[1] = entry;
|
|
for (int i = 2; i < sectionItemCount; i++)
|
|
{
|
|
sfa.ReadUInt16(); sfa.ReadUInt16();
|
|
sectionOffsets[i] = sfa.ReadUInt32();
|
|
}
|
|
|
|
sfa.PositionStream = offsetScript;
|
|
|
|
fileStrings = new List<sceStrings>();
|
|
|
|
if (parse)
|
|
{
|
|
instructions = Parse(sfa, fileStrings);
|
|
//order the offsets by string position
|
|
fileStrings.Sort((s1, s2) => s1.offset.CompareTo(s2.offset));
|
|
|
|
for (int index = 0; index < fileStrings.Count; ++index)
|
|
fileStrings[index].ReadData(sfa);
|
|
}
|
|
}
|
|
|
|
private void parse0x40(StreamFunctionAdd sfa, List<byte> data)
|
|
{
|
|
byte bass = sfa.ReadByte();
|
|
data.Add(bass);
|
|
|
|
byte n = sfa.ReadByte();
|
|
data.Add(n);
|
|
|
|
switch (n >> 6)
|
|
{
|
|
case 1:
|
|
data.Add(sfa.ReadByte());
|
|
break;
|
|
case 2:
|
|
data.Add(sfa.ReadByte());
|
|
data.Add(sfa.ReadByte());
|
|
break;
|
|
case 3:
|
|
data.Add(sfa.ReadByte());
|
|
data.Add(sfa.ReadByte());
|
|
data.Add(sfa.ReadByte());
|
|
break;
|
|
}
|
|
|
|
uint mask = (uint)(bass >> 2) & 7;
|
|
if (mask >= 2 && mask <= 5)
|
|
{
|
|
return;
|
|
}
|
|
|
|
mask = (uint)(n >> 4) & 3;
|
|
if (mask == 1)
|
|
{
|
|
data.Add(sfa.ReadByte());
|
|
}
|
|
else if (mask == 2)
|
|
{
|
|
data.Add(sfa.ReadByte());
|
|
data.Add(sfa.ReadByte());
|
|
}
|
|
else if (mask == 3)
|
|
{
|
|
data.Add(sfa.ReadByte());
|
|
data.Add(sfa.ReadByte());
|
|
data.Add(sfa.ReadByte());
|
|
}
|
|
}
|
|
|
|
private void parse0x20(StreamFunctionAdd sfa, List<byte> data)
|
|
{
|
|
byte n = sfa.ReadByte();
|
|
data.Add(n);
|
|
|
|
switch ((n >> 2) & 3)
|
|
{
|
|
case 1:
|
|
data.Add(sfa.ReadByte());
|
|
break;
|
|
case 2:
|
|
data.Add(sfa.ReadByte());
|
|
data.Add(sfa.ReadByte());
|
|
break;
|
|
case 3:
|
|
data.Add(sfa.ReadByte());
|
|
data.Add(sfa.ReadByte());
|
|
data.Add(sfa.ReadByte());
|
|
data.Add(sfa.ReadByte());
|
|
break;
|
|
}
|
|
}
|
|
private void parse0x80(StreamFunctionAdd sfa, List<byte> data)
|
|
{
|
|
byte n = sfa.ReadByte();
|
|
data.Add(n);
|
|
|
|
if ((n & 0x40) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
n = sfa.ReadByte();
|
|
data.Add(n);
|
|
|
|
int mask = (n >> 3) & 7;
|
|
if (mask == 2)
|
|
{
|
|
data.Add(sfa.ReadByte());
|
|
}
|
|
else if (mask == 3)
|
|
{
|
|
data.Add(sfa.ReadByte());
|
|
data.Add(sfa.ReadByte());
|
|
}
|
|
}
|
|
|
|
public Dictionary<long, sceInstruction> Parse(StreamFunctionAdd sfa, List<sceStrings> fileStrings)
|
|
{
|
|
var fileInstructions = new Dictionary<long, sceInstruction>();
|
|
instructionOffsets = new List<long>();
|
|
List<byte> temp;
|
|
uint branchTarget;
|
|
|
|
while (sfa.GetPosition() < this.offsetStrings - 1)
|
|
{
|
|
temp = new List<byte>();
|
|
// Parse the opcode
|
|
long position = sfa.GetPosition() - offsetScript;
|
|
instructionOffsets.Add(position);
|
|
byte currOpcode = sfa.ReadByte();
|
|
switch (currOpcode)
|
|
{
|
|
case 1:
|
|
case 2:
|
|
case 10:
|
|
temp.Add(currOpcode);
|
|
fileInstructions[position] = new sceInstruction(sceInstruction.sceOpcode.not_implemented, position, temp);
|
|
continue;
|
|
case 3:
|
|
branchTarget = sfa.ReadUInt24();
|
|
fileInstructions[position] = new sceInstruction(sceInstruction.sceOpcode.jmp, position, branchTarget, temp);
|
|
continue;
|
|
case 4:
|
|
branchTarget = sfa.ReadUInt24();
|
|
fileInstructions[position] = new sceInstruction(sceInstruction.sceOpcode.jzs, position, branchTarget, temp);
|
|
continue;
|
|
case 5:
|
|
branchTarget = sfa.ReadUInt24();
|
|
fileInstructions[position] = new sceInstruction(sceInstruction.sceOpcode.jnz, position, branchTarget, temp);
|
|
continue;
|
|
case 6:
|
|
branchTarget = sfa.ReadUInt24();
|
|
parse0x20(sfa, temp);
|
|
fileInstructions[position] = new sceInstruction(sceInstruction.sceOpcode.jne, position, branchTarget, temp);
|
|
continue;
|
|
case 7:
|
|
branchTarget = sfa.ReadUInt24();
|
|
parse0x20(sfa, temp);
|
|
parse0x20(sfa, temp);
|
|
fileInstructions[position] = new sceInstruction(sceInstruction.sceOpcode.jbt, position, branchTarget, temp);
|
|
continue;
|
|
case 8:
|
|
branchTarget = sfa.ReadUInt24();
|
|
fileInstructions[position] = new sceInstruction(sceInstruction.sceOpcode.cll, position, branchTarget, temp);
|
|
continue;
|
|
case 9:
|
|
temp.Add(currOpcode);
|
|
parse0x40(sfa, temp);
|
|
fileInstructions[position] = new sceInstruction(sceInstruction.sceOpcode.not_implemented, position, temp);
|
|
continue;
|
|
case 11:
|
|
temp.Add(currOpcode);
|
|
parse0x20(sfa, temp);
|
|
fileInstructions[position] = new sceInstruction(sceInstruction.sceOpcode.not_implemented, position, temp);
|
|
continue;
|
|
case 0x47:
|
|
byte num = sfa.ReadByte();
|
|
uint strOff = 0;
|
|
|
|
switch (num >> 6)
|
|
{
|
|
case 0:
|
|
strOff = (uint)num & 0xF;
|
|
fileStrings.Add(new sceStrings((uint)position, offsetStrings)
|
|
{
|
|
offset = strOff + offsetStrings,
|
|
typeOffset = sceStrings.OffsetType.ShortOffset
|
|
});
|
|
break;
|
|
case 1:
|
|
strOff = (uint)(num & 0xF) << 8 | sfa.ReadByte();
|
|
fileStrings.Add(new sceStrings((uint)position, offsetStrings)
|
|
{
|
|
offset = strOff + offsetStrings,
|
|
typeOffset = sceStrings.OffsetType.MediumOffset
|
|
});
|
|
break;
|
|
case 2:
|
|
strOff = (uint)(num & 0xF) << 16 | sfa.ReadUInt16();
|
|
fileStrings.Add(new sceStrings((uint)position, offsetStrings)
|
|
{
|
|
offset = strOff + offsetStrings,
|
|
typeOffset = sceStrings.OffsetType.LargeOffset
|
|
});
|
|
break;
|
|
case 3:
|
|
strOff = (uint)(num & 0xF) << 24 | sfa.ReadUInt24();
|
|
break;
|
|
}
|
|
|
|
if ((num >> 4 & 3) != 1)
|
|
{
|
|
throw new InvalidOperationException();
|
|
}
|
|
|
|
if (sfa.ReadByte() != 0) {
|
|
throw new InvalidOperationException();
|
|
}
|
|
|
|
fileInstructions[position] = new sceInstruction
|
|
{
|
|
opcode = sceInstruction.sceOpcode.str,
|
|
offset = position,
|
|
strTarget = strOff,
|
|
strExtra = 0,
|
|
size = 3 + (num >> 6)
|
|
|
|
};
|
|
fileStrings[fileStrings.Count - 1].instruction = fileInstructions[position];
|
|
continue;
|
|
}
|
|
|
|
if (currOpcode > 0x7F)
|
|
{
|
|
sfa.SetPosition(sfa.GetPosition() - 1);
|
|
parse0x80(sfa, temp);
|
|
fileInstructions[position] = new sceInstruction(sceInstruction.sceOpcode.not_implemented, position, temp);
|
|
continue;
|
|
}
|
|
if (currOpcode > 0xF && currOpcode < 0x20)
|
|
{
|
|
temp.Add(currOpcode);
|
|
int mask = (currOpcode >> 2) & 3;
|
|
if (mask == 1)
|
|
{
|
|
temp.Add(sfa.ReadByte());
|
|
}
|
|
if (mask == 2)
|
|
{
|
|
temp.Add(sfa.ReadByte());
|
|
temp.Add(sfa.ReadByte());
|
|
}
|
|
fileInstructions[position] = new sceInstruction(sceInstruction.sceOpcode.not_implemented, position, temp);
|
|
continue;
|
|
}
|
|
if (currOpcode > 0x1F && currOpcode < 0x30)
|
|
{
|
|
sfa.SetPosition(sfa.GetPosition() - 1);
|
|
parse0x20(sfa, temp);
|
|
fileInstructions[position] = new sceInstruction(sceInstruction.sceOpcode.not_implemented, position, temp);
|
|
continue;
|
|
}
|
|
if (currOpcode > 0x2F && currOpcode < 0x40)
|
|
{
|
|
temp.Add(currOpcode);
|
|
temp.Add(sfa.ReadByte()); temp.Add(sfa.ReadByte()); temp.Add(sfa.ReadByte()); temp.Add(sfa.ReadByte());
|
|
fileInstructions[position] = new sceInstruction(sceInstruction.sceOpcode.not_implemented, position, temp);
|
|
continue;
|
|
}
|
|
if (currOpcode > 0x3F && currOpcode < 0x80)
|
|
{
|
|
sfa.SetPosition(sfa.GetPosition() - 1);
|
|
parse0x40(sfa, temp);
|
|
fileInstructions[position] = new sceInstruction(sceInstruction.sceOpcode.not_implemented, position, temp);
|
|
continue;
|
|
}
|
|
}
|
|
return fileInstructions;
|
|
}
|
|
|
|
private void updateStringRef(sceInstruction inst, uint newTarget)
|
|
{
|
|
inst.strTarget = newTarget;
|
|
if(newTarget <= 0x0F)
|
|
{
|
|
inst.size = 3 + 0;
|
|
}
|
|
else if (newTarget <= 0xF_FF)
|
|
{
|
|
inst.size = 3 + 1;
|
|
}
|
|
else if (newTarget <= 0xF_FF_FF)
|
|
{
|
|
inst.size = 3 + 2;
|
|
}
|
|
else if (newTarget <= 0xF_FF_FF_FF)
|
|
{
|
|
inst.size = 3 + 3;
|
|
}
|
|
}
|
|
|
|
public void WriteStrings(StreamFunctionAdd sfa, bool dedup = false)
|
|
{
|
|
sfa.PositionStream = offsetStrings;
|
|
sfa.LengthStream = offsetStrings;
|
|
bool matched = false;
|
|
uint mockStringOffset = 0;
|
|
uint off;
|
|
for (int index = 0; index < fileStrings.Count; ++index)
|
|
{
|
|
if (dedup)
|
|
{
|
|
for (int index1 = index - 1; index1 >= 0; --index1)
|
|
{
|
|
if (index == 0) break;
|
|
if (fileStrings[index].data.Count == fileStrings[index1].data.Count)
|
|
{
|
|
if (System.Linq.Enumerable.SequenceEqual(fileStrings[index].data, fileStrings[index1].data))
|
|
{
|
|
fileStrings[index].offset = fileStrings[index1].offset;
|
|
updateStringRef(fileStrings[index].instruction, fileStrings[index1].offset);
|
|
fileStrings[index].isDeduped = true;
|
|
matched = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (matched)
|
|
continue;
|
|
}
|
|
fileStrings[index].offset = mockStringOffset;
|
|
updateStringRef(fileStrings[index].instruction, fileStrings[index].offset);
|
|
mockStringOffset += (uint)fileStrings[index].data.Count;
|
|
}
|
|
|
|
int sizeStart = instructions[instructionOffsets[0]].size;
|
|
for (int i = 1; i < instructionOffsets.Count; i++)
|
|
{
|
|
off = (uint)instructionOffsets[i];
|
|
instructions[off].offset = sizeStart;
|
|
sizeStart += instructions[off].size;
|
|
}
|
|
|
|
for (int i = 0; i < instructionOffsets.Count; i++)
|
|
{
|
|
off = (uint)instructionOffsets[i];
|
|
if (instructions[off].opcode == sceInstruction.sceOpcode.not_implemented
|
|
|| instructions[off].opcode == sceInstruction.sceOpcode.str)
|
|
{
|
|
continue;
|
|
}
|
|
uint tgt = instructions[off].branchTarget;
|
|
instructions[off].branchTarget = (uint)instructions[tgt].offset;
|
|
}
|
|
|
|
sectionOffsets[0] = (uint)instructions[sectionOffsets[0]].offset;
|
|
sectionOffsets[1] = (uint)instructions[sectionOffsets[1]].offset;
|
|
for (int i = 2; i < sectionItemCount; i++)
|
|
{
|
|
sectionOffsets[i] = (uint)instructions[sectionOffsets[i]].offset;
|
|
}
|
|
|
|
sfa.SetPosition(offsetScript);
|
|
|
|
for (int i = 0; i < instructionOffsets.Count; i++)
|
|
{
|
|
off = (uint)instructionOffsets[i];
|
|
switch (instructions[off].opcode)
|
|
{
|
|
case sceInstruction.sceOpcode.not_implemented:
|
|
sfa.WriteBytes(instructions[off].rawBytes);
|
|
continue;
|
|
|
|
case sceInstruction.sceOpcode.jmp:
|
|
case sceInstruction.sceOpcode.jzs:
|
|
case sceInstruction.sceOpcode.jnz:
|
|
case sceInstruction.sceOpcode.cll:
|
|
case sceInstruction.sceOpcode.jne:
|
|
case sceInstruction.sceOpcode.jbt:
|
|
sfa.WriteByte((byte)instructions[off].opcode);
|
|
sfa.WriteUInt24(instructions[off].branchTarget);
|
|
sfa.WriteBytes(instructions[off].operands);
|
|
break;
|
|
|
|
case sceInstruction.sceOpcode.str:
|
|
sfa.WriteByte((byte)instructions[off].opcode);
|
|
byte num = 0x10;
|
|
switch (instructions[off].size - 3)
|
|
{
|
|
case 0:
|
|
num |= 0 << 6;
|
|
num |= (byte)(instructions[off].strTarget & 0xF);
|
|
sfa.WriteByte(num);
|
|
break;
|
|
case 1:
|
|
num |= 1 << 6;
|
|
num |= (byte)((instructions[off].strTarget >> 8) & 0xF);
|
|
sfa.WriteByte(num);
|
|
sfa.WriteByte((byte)instructions[off].strTarget);
|
|
break;
|
|
case 2:
|
|
num |= 2 << 6;
|
|
num |= (byte)((instructions[off].strTarget >> 16) & 0xF);
|
|
sfa.WriteByte(num);
|
|
sfa.WriteUInt16((ushort)instructions[off].strTarget);
|
|
break;
|
|
case 3:
|
|
num |= 3 << 6;
|
|
num |= (byte)((instructions[off].strTarget >> 24) & 0xF);
|
|
sfa.WriteByte(num);
|
|
sfa.WriteUInt24(instructions[off].strTarget & 0xFF_FF_FF);
|
|
break;
|
|
}
|
|
sfa.WriteByte(0);
|
|
break;
|
|
}
|
|
}
|
|
sfa.WriteByte(0);
|
|
offsetStrings = (uint)sfa.GetPosition();
|
|
foreach (sceStrings str in fileStrings)
|
|
{
|
|
str.WriteData(sfa);
|
|
}
|
|
sfa.WriteByte(0);
|
|
|
|
sfa.SetPosition(0xC);
|
|
sfa.WriteUInt32(offsetStrings); sfa.ReadUInt32();
|
|
sfa.WriteUInt32(sectionOffsets[0]);
|
|
sfa.WriteUInt32(sectionOffsets[1]);
|
|
sfa.SetPosition(0x34);
|
|
for (int i = 2; i < sectionItemCount; i++)
|
|
{
|
|
sfa.ReadUInt32();
|
|
sfa.WriteUInt32(sectionOffsets[i]);
|
|
}
|
|
}
|
|
}
|
|
} |