summaryrefslogtreecommitdiff
path: root/NW4RTools/BrresWriter.cs
blob: 5590ab541bd0518baca470392e87879f59a728b7 (plain)
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
	}
}