Skip to content

Commit 6c08d6e

Browse files
committed
New tool: Names2CSV
1 parent a078d1b commit 6c08d6e

File tree

9 files changed

+676
-2
lines changed

9 files changed

+676
-2
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ The first and only 1998 Gangsters Organized Crime MOD
1414
## Tools
1515
* __XLSX2Data__ - Batch create TXT files quickly and easily. Edit all your data directly in a familiar spreadsheet format. No more need to convert or open them in separate programs.
1616
* __SPRTYL2PNG__ - Show, replace or export any game gfx resource *.spr and *.tyl files. Support full transparency with PNG import/export.
17-
* __HELP2CSV__ - Converts help/tooltips files (*.idx *.dat) to CSV.
17+
* __Names2CSV__ - Convert `Names.dat` files to CSV format and vice versa.
18+
* __Help2CSV__ - Converts help/tooltips files (*.idx *.dat) to CSV.
1819
* __XTX2TXT__ - Converter for XTX files.
1920

2021
## How to install?

Tools/Names2CSV/App.config

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<configuration>
3+
<startup>
4+
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8.1" />
5+
</startup>
6+
</configuration>

Tools/Names2CSV/HuffmanTree.cs

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
5+
namespace Names2CSV
6+
{
7+
public static class HuffmanTree
8+
{
9+
private class HuffmanNode : IComparable<HuffmanNode>
10+
{
11+
public HuffmanNode Left { get; set; }
12+
public HuffmanNode Right { get; set; }
13+
public byte Symbol { get; set; }
14+
public int Frequency { get; set; }
15+
16+
public bool IsLeaf => Left == null && Right == null;
17+
18+
public HuffmanNode(byte symbol = 0, int frequency = 0)
19+
{
20+
Symbol = symbol;
21+
Frequency = frequency;
22+
}
23+
24+
public HuffmanNode(HuffmanNode left, HuffmanNode right)
25+
{
26+
Left = left;
27+
Right = right;
28+
Frequency = left.Frequency + right.Frequency;
29+
}
30+
31+
public HuffmanNode(MemoryStream data)
32+
{
33+
byte children = (byte)data.ReadByte();
34+
for (int i = 0; i < children; i++)
35+
{
36+
byte direction = (byte)data.ReadByte();
37+
if (direction == (byte)'L')
38+
Left = new HuffmanNode(data);
39+
else if (direction == (byte)'R')
40+
Right = new HuffmanNode(data);
41+
}
42+
Symbol = (byte)data.ReadByte();
43+
}
44+
45+
public int CompareTo(HuffmanNode other)
46+
{
47+
if (other == null) return 1;
48+
return Frequency.CompareTo(other.Frequency) != 0
49+
? Frequency.CompareTo(other.Frequency)
50+
: Symbol.CompareTo(other.Symbol);
51+
}
52+
}
53+
54+
public static void Decode(MemoryStream input, MemoryStream output)
55+
{
56+
var root = new HuffmanNode(input);
57+
var currentNode = root;
58+
int currentByte;
59+
60+
while ((currentByte = input.ReadByte()) != -1)
61+
{
62+
for (int bitMask = 128; bitMask != 0; bitMask >>= 1)
63+
{
64+
currentNode = (currentByte & bitMask) == 0 ? currentNode.Left : currentNode.Right;
65+
66+
if (currentNode.IsLeaf)
67+
{
68+
output.WriteByte(currentNode.Symbol);
69+
currentNode = root;
70+
}
71+
}
72+
}
73+
}
74+
75+
private static SortedDictionary<byte, int> CalculateFrequencies(MemoryStream memoryStream)
76+
{
77+
memoryStream.Position = 0;
78+
var frequencies = new SortedDictionary<byte, int>();
79+
int byteValue;
80+
81+
while ((byteValue = memoryStream.ReadByte()) != -1)
82+
{
83+
if (!frequencies.ContainsKey((byte)byteValue))
84+
frequencies[(byte)byteValue] = 0;
85+
86+
frequencies[(byte)byteValue]++;
87+
}
88+
89+
return frequencies;
90+
}
91+
92+
private static HuffmanNode BuildTree(SortedDictionary<byte, int> frequencies)
93+
{
94+
var nodeList = new List<HuffmanNode>();
95+
foreach (var kvp in frequencies)
96+
nodeList.Add(new HuffmanNode(kvp.Key, kvp.Value));
97+
98+
while (nodeList.Count > 1)
99+
{
100+
nodeList.Sort();
101+
var left = nodeList[0];
102+
var right = nodeList[1];
103+
104+
nodeList.RemoveRange(0, 2);
105+
106+
var parent = new HuffmanNode(left, right);
107+
nodeList.Add(parent);
108+
}
109+
110+
return nodeList[0];
111+
}
112+
113+
private static void GenerateCodes(HuffmanNode node, List<bool> code, Dictionary<byte, List<bool>> codes)
114+
{
115+
if (node.IsLeaf)
116+
{
117+
codes[node.Symbol] = new List<bool>(code);
118+
return;
119+
}
120+
121+
code.Add(false);
122+
GenerateCodes(node.Left, code, codes);
123+
code.RemoveAt(code.Count - 1);
124+
125+
code.Add(true);
126+
GenerateCodes(node.Right, code, codes);
127+
code.RemoveAt(code.Count - 1);
128+
}
129+
130+
private static Dictionary<byte, List<bool>> GenerateHuffmanCodes(HuffmanNode root)
131+
{
132+
var huffmanCodes = new Dictionary<byte, List<bool>>();
133+
GenerateCodes(root, new List<bool>(), huffmanCodes);
134+
return huffmanCodes;
135+
}
136+
137+
public static void Encode(MemoryStream input, MemoryStream output)
138+
{
139+
var frequencies = CalculateFrequencies(input);
140+
var root = BuildTree(frequencies);
141+
SerializeNode(root, output);
142+
var huffmanCodes = GenerateHuffmanCodes(root);
143+
144+
input.Position = 0;
145+
146+
byte current = 0;
147+
byte bitValue = 128;
148+
int byteValue;
149+
150+
while ((byteValue = input.ReadByte()) != -1)
151+
{
152+
var code = huffmanCodes[(byte)byteValue];
153+
foreach (var bit in code)
154+
{
155+
if (bit) current += bitValue;
156+
bitValue >>= 1;
157+
if (bitValue == 0)
158+
{
159+
output.WriteByte(current);
160+
current = 0;
161+
bitValue = 128;
162+
}
163+
}
164+
}
165+
166+
if (bitValue != 128)
167+
{
168+
var zero = huffmanCodes[0];
169+
foreach (var bit in zero)
170+
{
171+
if (bit) current += bitValue;
172+
bitValue >>= 1;
173+
}
174+
output.WriteByte(current);
175+
}
176+
}
177+
178+
private static void SerializeNode(HuffmanNode node, MemoryStream stream)
179+
{
180+
if (node.Left == null && node.Right == null)
181+
{
182+
stream.WriteByte(0);
183+
}
184+
else
185+
{
186+
stream.WriteByte(2);
187+
if (node.Left != null)
188+
{
189+
stream.WriteByte((byte)'L');
190+
SerializeNode(node.Left, stream);
191+
}
192+
if (node.Right != null)
193+
{
194+
stream.WriteByte((byte)'R');
195+
SerializeNode(node.Right, stream);
196+
}
197+
}
198+
stream.WriteByte(node.Symbol);
199+
}
200+
}
201+
}

0 commit comments

Comments
 (0)