forked from JeremieCHN/MetaDataStringEditor
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathMetadataFile.cs
More file actions
138 lines (114 loc) · 5.13 KB
/
MetadataFile.cs
File metadata and controls
138 lines (114 loc) · 5.13 KB
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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace MetaDataStringEditor {
class MetadataFile : IDisposable {
public BinaryReader reader;
private uint stringLiteralOffset;
private uint stringLiteralCount;
private long DataInfoPosition;
private uint stringLiteralDataOffset;
private uint stringLiteralDataCount;
private List<StringLiteral> stringLiterals = new List<StringLiteral>();
public List<byte[]> strBytes = new List<byte[]>();
public MetadataFile(string fullName) {
reader = new BinaryReader(File.OpenRead(fullName));
// Read file
ReadHeader();
// Read string
ReadLiteral();
ReadStrByte();
Logger.I("Basic read completed");
}
private void ReadHeader() {
Logger.I("Read head");
uint vansity = reader.ReadUInt32();
if (vansity != 0xFAB11BAF) {
throw new Exception("Flag check failed");
}
int version = reader.ReadInt32();
stringLiteralOffset = reader.ReadUInt32(); // The position of the list area will not be changed later
stringLiteralCount = reader.ReadUInt32(); // The size of the list area, will not be changed later
DataInfoPosition = reader.BaseStream.Position; // Make a note of your current position, use it later
stringLiteralDataOffset = reader.ReadUInt32(); // The location of the data area may need to be changed
stringLiteralDataCount = reader.ReadUInt32(); // The length of the data area may need to be changed
}
private void ReadLiteral() {
Logger.I("读取Literal");
ProgressBar.SetMax((int)stringLiteralCount / 8);
reader.BaseStream.Position = stringLiteralOffset;
for (int i = 0; i < stringLiteralCount / 8; i++) {
stringLiterals.Add(new StringLiteral {
Length = reader.ReadUInt32(),
Offset = reader.ReadUInt32()
});
ProgressBar.Report();
}
}
private void ReadStrByte() {
Logger.I("Read string Bytes");
ProgressBar.SetMax(stringLiterals.Count);
for (int i = 0; i < stringLiterals.Count; i++) {
reader.BaseStream.Position = stringLiteralDataOffset + stringLiterals[i].Offset;
strBytes.Add(reader.ReadBytes((int)stringLiterals[i].Length));
ProgressBar.Report();
}
}
public void WriteToNewFile(string fileName) {
BinaryWriter writer = new BinaryWriter(File.Create(fileName));
// Copy all first
reader.BaseStream.Position = 0;
reader.BaseStream.CopyTo(writer.BaseStream);
// Update Literal
Logger.I("Update Literal");
ProgressBar.SetMax(stringLiterals.Count);
writer.BaseStream.Position = stringLiteralOffset;
uint count = 0;
for (int i = 0; i < stringLiterals.Count; i++) {
stringLiterals[i].Offset = count;
stringLiterals[i].Length = (uint)strBytes[i].Length;
writer.Write(stringLiterals[i].Length);
writer.Write(stringLiterals[i].Offset);
count += stringLiterals[i].Length;
ProgressBar.Report();
}
// Once aligned, I'm not sure if it is necessary, but Unity did it, so it is better to add it
var tmp = (stringLiteralDataOffset + count) % 4;
if (tmp != 0) count += 4 - tmp;
// Check if there is enough space
if (count > stringLiteralDataCount) {
// Check if there is any other data behind the data area. If not, you can directly extend the data area.
if (stringLiteralDataOffset + stringLiteralDataCount < writer.BaseStream.Length) {
// The original space is not enough, nor can it be extended directly, so the whole is moved to the end of the file
stringLiteralDataOffset = (uint)writer.BaseStream.Length;
}
}
stringLiteralDataCount = count;
// Write string
Logger.I("Write String");
ProgressBar.SetMax(strBytes.Count);
writer.BaseStream.Position = stringLiteralDataOffset;
for (int i = 0; i < strBytes.Count; i++) {
writer.Write(strBytes[i]);
ProgressBar.Report();
}
// Update header
Logger.I("Update header");
writer.BaseStream.Position = DataInfoPosition;
writer.Write(stringLiteralDataOffset);
writer.Write(stringLiteralDataCount);
Logger.I("Update completed");
writer.Close();
}
public void Dispose() {
reader?.Dispose();
}
public class StringLiteral {
public uint Length;
public uint Offset;
}
}
}