-
Notifications
You must be signed in to change notification settings - Fork 29
/
DMsgParser.cs
executable file
·131 lines (106 loc) · 3.37 KB
/
DMsgParser.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
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
namespace ResourceExtractor;
internal class DMsgParser {
internal static dynamic[] Parse(Stream stream, IDictionary<int, string> fields) {
var header = stream.Read<Header>(0);
if (header.Format != 0x00000067736D5F64) {
throw new InvalidOperationException("Invalid data format.");
}
if (header.Version != 0x0000000300000003) {
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Invalid format version. [{0:X8}]", header.Version));
}
long[] table;
if (header.TableSize != 0) {
if (header.TableSize != header.Count * 8 || header.EntrySize != 0) {
throw new InvalidOperationException("Data is corrupt.");
}
table = stream.ReadArray<long>(header.Count, header.HeaderSize);
} else {
if (header.DataSize != header.Count * header.EntrySize) {
throw new InvalidOperationException("Data is corrupt.");
}
table = [];
}
stream.Position = header.HeaderSize + header.TableSize;
var data = new byte[header.DataSize];
stream.Read(data, 0, data.Length);
if (header.Encrypted) {
for (var i = 0; i < table.Length; i++) {
table[i] = ~table[i];
}
for (var i = 0; i < data.Length; i++) {
data[i] = (byte) ~data[i];
}
}
dynamic objects = new ModelObject[header.Count];
var length = (int) header.EntrySize;
for (var i = 0; i < objects.Length; i++) {
int offset;
if (header.TableSize != 0) {
length = (int) (table[i] >> 32);
offset = (int) table[i];
} else {
offset = i * (int) header.EntrySize;
}
var count = BitConverter.ToInt32(data, offset);
dynamic resource = new ModelObject();
for (var j = 0; j < count; j++) {
if (!fields.ContainsKey(j)) {
continue;
}
var entryoffset = BitConverter.ToInt32(data, offset + j * 8 + 4) + offset;
var entrytype = BitConverter.ToInt32(data, offset + j * 8 + 8);
dynamic value;
switch (entrytype) {
case 0:
entryoffset += 0x1C;
var stringlength = 0;
for (var k = 0; k < length; k++) {
if (data[entryoffset + k] == 0) {
break;
}
stringlength++;
}
value = ShiftJISFF11Encoding.ShiftJISFF11.GetString(data, entryoffset, stringlength);
break;
case 1:
value = BitConverter.ToInt32(data, entryoffset);
break;
default:
value = null;
break;
}
resource[fields[j]] = value;
}
objects[i] = resource;
}
return objects;
}
[SuppressMessage("Style", "IDE0032:Use auto property", Justification = "Messes up struct layout")]
[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 64)]
private readonly struct Header {
private readonly long format;
private readonly short unknown;
private readonly byte encrypted;
private readonly long version;
private readonly uint filesize;
private readonly uint headersize;
private readonly uint tablesize;
private readonly uint entrysize;
private readonly int datasize;
private readonly int count;
public long Format => format;
public bool Encrypted => encrypted != 0;
public long Version => version;
public uint HeaderSize => headersize;
public uint TableSize => tablesize;
public uint EntrySize => entrysize;
public int DataSize => datasize;
public int Count => count;
}
}