-
Notifications
You must be signed in to change notification settings - Fork 0
/
SkitProcessing.cs
106 lines (93 loc) · 3.57 KB
/
SkitProcessing.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
using System;
using System.Collections.Generic;
using System.IO;
using HyoutaPluginBase;
using HyoutaTools.Tales.Graces.SCS;
using HyoutaUtils;
namespace ToGLocInject {
internal static class SkitProcessing {
private static bool MatchesSkitFormat(string s) {
int idx = s.IndexOf("\x1F(1,");
if (idx < 0) {
return false;
}
int idx2 = s.IndexOf(")", idx);
if (idx2 < 0) {
return false;
}
if (idx2 + 1 != s.Length) {
return false;
}
return true;
}
private static void PutString(List<string> newscs, string v, int currentIndex) {
while (!(currentIndex < newscs.Count)) {
newscs.Add("");
}
newscs[currentIndex] = v;
}
// some skit files reuse the same JP string in cases where the english text is different, this expands this to have a separate entry for each JP string
public static (Stream newTssStream, SCS wscsnew) MultiplyOutSkitTss(DuplicatableStream stream, SCS wscsorig) {
stream.Position = 0;
Stream s = stream.CopyToMemory();
uint magic = s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian);
uint codeStart = s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian);
uint unknown3 = s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian);
uint dataStart = s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian);
uint unknown5 = s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian);
uint codeLength = s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian);
uint dataLength = s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian);
uint unknown8 = s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian);
List<(long pos, int number, long len)> strings = new List<(long pos, int number, long len)>();
s.Position = codeStart;
while (s.Position < (codeStart + codeLength + 0xC - 1)) {
if (s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian) == 0x01000000) {
if (s.PeekUInt64().FromEndian(EndianUtils.Endianness.BigEndian) == 0x0E000008040C0004) {
s.DiscardBytes(8);
uint offsetOfOffset = s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian);
long pos = s.Position;
s.Position = dataStart + offsetOfOffset;
uint offset = s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian);
long stringpos = dataStart + offset;
s.Position = stringpos;
string str = s.ReadNulltermString(TextUtils.GameTextEncoding.ShiftJIS);
// must have specific format
if (MatchesSkitFormat(str)) {
int num = SCS.DecodeNumber(str.Substring(4, str.Length - 5));
strings.Add((stringpos, num, str.Length));
}
s.Position = pos;
}
}
}
SortedSet<int> reservedNumbers = new SortedSet<int>();
for (int i = 0; i < wscsorig.Entries.Count; ++i) {
reservedNumbers.Add(i);
}
foreach (var d in strings) {
if (reservedNumbers.Contains(d.number)) {
reservedNumbers.Remove(d.number);
}
}
List<string> newscs = new List<string>(wscsorig.Entries);
List<(int oldIdx, int newIdx)> idxs = new List<(int oldIdx, int newIdx)>();
int currentIndex = 0;
foreach (var d in strings) {
while (reservedNumbers.Contains(currentIndex)) {
++currentIndex;
}
string numstr = SCS.EncodeNumber(currentIndex);
string resultstr = "\x1F(1," + numstr + ")";
if (resultstr.Length > d.len) {
throw new Exception("don't know how to inject this");
}
s.Position = d.pos;
s.WriteShiftJisNullterm(resultstr);
PutString(newscs, wscsorig.Entries[d.number], currentIndex);
++currentIndex;
}
s.Position = 0;
return (s, new SCS(newscs));
}
}
}