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
|
using System;
using System.Collections;
using System.Collections.Generic;
using NW4RTools.Models;
namespace NW4RTools {
public class BrresWriter {
public static byte[] WriteFile(ResFile file) {
return new BrresWriter().Save(file);
}
private ResFile File;
private ILogger Debug;
private SortedDictionary<int, string> OffsetMap;
private OutputStream Output;
private BrresWriter() {
Debug = new ConsoleLogger();
OffsetMap = new SortedDictionary<int, string>();
}
private byte[] Save(ResFile file) {
Output = new OutputStream(ByteEndian.BigEndian);
File = file;
using (var c = Debug.Push("Offset Calculation"))
CalculateRoot();
Output.WriteBytes(StringTableData.GetBuffer());
return Output.GetBuffer();
}
// OK, here's how I'm going to code this: kinda like how BrawlLib works, first I'll calculate the size of
// each written element, and use that to build up a list of offsets. Then, I'll actually write out the data.
// This code will also handle building the string table.
#region Offset/String Table Calculation
private int CurrentPos;
private void CalculateRoot() {
// Where it all starts!
InitialiseStringTable();
// First up: BRRES header
CurrentPos = 0x10;
// First block, and ResDict
CurrentPos += 8;
CurrentPos += GetSizeForResDict(File);
// Now do each ResDict in the File
foreach (object dict in File.Values) {
CurrentPos += GetSizeForResDict(dict as ResDict<object>);
}
// OK, so that's done. Process each type
foreach (var name in File.Keys) {
AddString(name);
switch (name) {
case "3DModels(NW4R)":
// do that stuff
break;
default:
Debug.Send("[[ UNIMPLEMENTED {0} ]]", name);
break;
}
}
// ... and done with that. Build the string table and go!
CalculateStringTable();
}
private int GetSizeForResDict(ResDict<object> dict) {
return 8 + ((dict.Count + 1) * 0x10);
}
#endregion
#region String Table Handling
// Contains the strings while they're being pulled from the ResFile data
private List<string> StringTable;
// Once every string used in the .brres is found, CalculateStringTable() is called, which
// writes the table to an OutputStream and saves every offset
private Dictionary<string, int> StringTableOffsets;
private OutputStream StringTableData;
// Called at the start of the process
private void InitialiseStringTable() {
StringTable = new List<string>();
}
private void AddString(string str) {
if (!StringTable.Contains(str)) {
StringTable.Add(str);
}
}
private void CalculateStringTable() {
StringTable.Sort();
StringTableOffsets = new Dictionary<string, int>();
StringTableData = new OutputStream(ByteEndian.BigEndian);
foreach (var s in StringTable) {
// Add 4 because the Names are referenced by the string data, and not by the ResName struct itself
StringTableOffsets[s] = StringTableData.Position + 4;
StringTableData.WriteName(s);
}
}
#endregion
}
}
|