-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathProgram.cs
182 lines (153 loc) · 7.06 KB
/
Program.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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using uSource.Formats.Extensions;
using uSource.Formats;
namespace WwisePCKUnpacker
{
class Program
{
static bool WithSFX = false;
static int SelectedLang = 0;
const string EXTRACT_SFX_TOO = "Extract sfx too? ";
const string PLEASE_SELECT_LANGUAGE = "Please select language: ";
static PackageHeader Header;
static StringMap[] LanguageMaps;
static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("Input file...");
Console.ReadKey();
return;
}
Console.WriteLine($"Input: {args[0]}\n");
FileInfo fileInfo = new FileInfo(args[0].NormalizeSlashes());
if (!fileInfo.Exists)
throw new FileLoadException("File not found...");
using (uReader reader = new uReader(fileInfo.OpenRead()))
{
#region Header
Header = new PackageHeader();
reader.ReadType(ref Header);
Console.WriteLine(Header);
if (Header.HeaderID != PackageHeader.AK_PACKAGE_ID)
throw new FileLoadException("Invalid HeaderID");
#region Languages
uint numLangs = reader.ReadUInt32();
Console.WriteLine($"Language count: {numLangs}");
LanguageMaps = new StringMap[numLangs];
for (int i = 0; i < numLangs; i++)
{
LanguageMaps[i].offset = reader.ReadUInt32();
LanguageMaps[i].id = reader.ReadUInt32();
}
for (int i = 0; i < numLangs; i++)
LanguageMaps[i].key = reader.ReadNullTerminatedString(Encoding.Unicode);
// resort result (lowest -> highest)
LanguageMaps = LanguageMaps.OrderBy(x => x.id).ToArray();
// alignment current offset to 4
reader.AlignSeek(4);
#endregion
#region Banks
uint numBanks = reader.ReadUInt32();
Console.WriteLine($"Banks count: {numBanks}");
FileLUT[] banks = GetFileEntries(reader, numBanks);
#endregion
#region Streamed
uint numStreams = reader.ReadUInt32();
Console.WriteLine($"Streams count: {numStreams}");
FileLUT[] streams = GetFileEntries(reader, numStreams);
#endregion
#region External
uint numExternals = reader.ReadUInt32();
Console.WriteLine($"Externals count: {numExternals}\n");
FileLUT[] externals = GetFileEntries(reader, numExternals, true);
#endregion
#endregion
#region Common (Selecting language & etc..)
// print available languages
for (int i = 0; i < LanguageMaps.Length; i++)
{
StringMap lang = LanguageMaps[i];
Console.WriteLine($"{lang.id} - {lang.GetKeyName()}");
}
Console.Write(PLEASE_SELECT_LANGUAGE);
while (!int.TryParse(Console.ReadLine(), out SelectedLang))
Console.Write(PLEASE_SELECT_LANGUAGE);
Console.WriteLine($"Selected: {LanguageMaps[SelectedLang].GetKeyName()}\n");
if (SelectedLang != FileLUT.AK_INVALID_LANGUAGE_ID)
{
char tempChar = '0';
Console.WriteLine($"{EXTRACT_SFX_TOO} y - yes | n - no");
while (!((WithSFX = tempChar == 'y') || tempChar == 'n'))
tempChar = Console.ReadKey().KeyChar;
}
#endregion
// TODO: not sure if it works correctly with all files
ExtractEntries(banks, reader, "Bank");
ExtractEntries(streams, reader, "Streamed");
ExtractEntries(externals, reader, "External");
}
Console.WriteLine("\nDone. Press any key to close.");
Console.ReadKey();
}
static void ExtractEntries(FileLUT[] entries, uReader reader, string suffix)
{
if (entries.Length == 0)
return;
for (int i = 0; i < entries.Length; i++)
{
FileLUT entry = entries[i];
StringMap language = LanguageMaps[entry.uLanguageID];
// alignment current offset to block size (2048 by default)
reader.AlignSeek(entry.uBlockSize);
if (language.id == SelectedLang || (WithSFX && language.id == FileLUT.AK_INVALID_LANGUAGE_ID) || SelectedLang == 0)
{
// remember position before writing
long currPos = reader.BaseStream.Position;
// trying parse name
reader.BaseStream.Position += 122;
string fileName = entry.uFileID.ToString();
if (reader.ReadInt32() == 1414744396) //LIST
{
reader.BaseStream.Position += 20;
fileName = reader.ReadNullTerminatedString();
}
// build output path & make sure if path exist, otherwise create it (folder & subfolders)
string savePath = PathExtension.ProjectPath + language.key;
DirectoryInfo dirInfo = new DirectoryInfo(savePath);
if (!dirInfo.Exists)
dirInfo.Create();
// offset back to start writing file
reader.BaseStream.Position = currPos;
// writing to file...
fileName = $"{suffix}_{i}_{fileName}.wav";
using (BinaryWriter writer = new BinaryWriter(File.Create($"{savePath}{PathExtension.PathSeparator}{fileName}")))
writer.Write(reader.ReadBytes((int)entry.uFileSize));
Console.WriteLine(fileName);
}
else reader.BaseStream.Position += (long)entry.uFileSize;
}
}
static FileLUT[] GetFileEntries(uReader reader, uint numFiles, bool isUINT64 = false)
{
if (numFiles == 0)
return new FileLUT[0];
FileLUT[] files = new FileLUT[numFiles];
for (int i = 0; i < numFiles; i++)
{
files[i].uFileID = isUINT64 ? reader.ReadUInt64() : reader.ReadUInt32();
files[i].uBlockSize = reader.ReadUInt32();
files[i].uFileSize = reader.ReadUInt32();
files[i].uStartingBlock = reader.ReadUInt32();
files[i].uLanguageID = reader.ReadUInt32();
}
// not sure about sorting, but it looks ok
return files = files.OrderBy(x => x.uStartingBlock).ToArray();
}
}
}