forked from Marshallx/Launch-Base
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMarshallxCSFClass.cls
418 lines (407 loc) · 18.1 KB
/
MarshallxCSFClass.cls
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
Persistable = 0 'NotPersistable
DataBindingBehavior = 0 'vbNone
DataSourceBehavior = 0 'vbNone
MTSTransactionMode = 0 'NotAnMTSObject
END
Attribute VB_Name = "MarshallxCSFClass"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit
Private Type CSFLABEL
ValueID() As String * 4
Substrings As Long
LabelNameLength As Long
LabelName As String
ValueLength() As Long
Value() As String
ExtraValueLength() As Long
ExtraValue() As String
End Type
Private Type CSFFILEHEADER
HeaderID As String * 4 'CSF header identifier, must be " FSC".
Version As Long 'CSF Version (YR uses 3, unknown what the difference is)
Labels As Long 'Total number of labels.
ExtraValues As Long 'Total number of extra values.
Zippo As Long 'Unused by the game.
Language As Long 'Language of the string table. See below for a list.
'0 = US (English)*
'1 = UK (English)
'2 = German*
'3 = French*
'4 = Spanish
'5 = Italian
'6 = Japanese
'7 = Jabberwockie
'8 = Korean*
'9 = Chinese*
'>9 = Unknown
'*RA2/YR has been released in this language.
End Type
Private thisCSFPath As String 'path last loaded from / default to load from next time
Private thisCSFHeader As CSFFILEHEADER
Private thisLabels() As CSFLABEL
Private thisLabelPos As Integer
'Public Type CSFLABELHEADER
' LabelID As String * 4 'Label header identifier, must be " LBL" otherwise read the next 4 bytes.
' Substrings As Long 'Total number of label values for this label, usually just 1.
' LabelNameLength As Long 'Size of the label name that follows.
' LabelName As String * LabelNameLength 'A non-zero-terminated string that is as long as the DWORD at 0x8 says. If it is longer, the rest will be cut off.
'End Type
'Public Type CSFLABELVALUE
' ValueID As String * 4 '" RTS" (no extra value) or "WRTS" (there is an extra value)
' ValueLength As Long 'This holds the length of the Unicode string (the value) that follows.
' Value As String * ValueLength 'This holds the encoded value of the label. Note that this is ValueLength*2 bytes long, because the value is a Unicode string, i.e. every character is a word instead of a byte. To decode the value to a Unicode string, not every byte of the value data (or substract it from 0xFF).
' ExtraValueLength As Long 'This holds the length of the extra value string that follow. This only applies if the identifier is "WRTS" and not " RTS".
' ExtraValue As String * ExtraValueLength 'Like the label name, a non-zero-terminated string that is as long as ExtraValueLength says. If it is longer, the rest will be cut off.
'End Type
Public Property Get LabelCount() As Long
LabelCount = thisCSFHeader.Labels
End Property
Public Property Get LabelName(ByVal iLabel As Long) As String
LabelName = thisLabels(iLabel).LabelName
End Property
Public Property Get Value(ByVal iLabel As Long) As String
'only gives access to first value
Value = thisLabels(iLabel).Value(1)
End Property
Public Property Get ExtraValue(ByVal iLabel As Long) As String
'only gives access to first value
If thisLabels(iLabel).ValueID(1) = "WRTS" Then
ExtraValue = thisLabels(iLabel).ExtraValue(1)
Else
ExtraValue = ""
End If
End Property
Public Sub Initialise(Optional ByVal iLanguage As Long = 0)
thisCSFPath = ""
thisCSFHeader.HeaderID = " FSC"
thisCSFHeader.Version = 3
thisCSFHeader.Labels = 0
thisCSFHeader.ExtraValues = 0
thisCSFHeader.Zippo = 0
thisCSFHeader.Language = iLanguage
ReDim thisLabels(500)
thisLabelPos = 0
End Sub
Public Sub SaveCSF(Optional ByVal sSavePath As String = "")
Dim hFile As Integer
Dim iLabel As Long
Dim iValue As Long
If sSavePath <> "" Then thisCSFPath = sSavePath
If FileExists(thisCSFPath) Then Call Kill(thisCSFPath)
hFile = FreeFile()
Open thisCSFPath For Binary As #hFile
Put #hFile, , thisCSFHeader
For iLabel = 1 To thisCSFHeader.Labels
Put #hFile, , " LBL"
Put #hFile, , thisLabels(iLabel).Substrings
Put #hFile, , thisLabels(iLabel).LabelNameLength
Put #hFile, , thisLabels(iLabel).LabelName
iValue = 1
Do While iValue <= thisLabels(iLabel).Substrings
Put #hFile, , thisLabels(iLabel).ValueID(iValue)
Put #hFile, , thisLabels(iLabel).ValueLength(iValue)
If thisLabels(iLabel).ValueLength(iValue) > 0 Then Put #hFile, , thisLabels(iLabel).Value(iValue)
If thisLabels(iLabel).ValueID(iValue) = "WRTS" Then
Put #hFile, , thisLabels(iLabel).ExtraValueLength(iValue)
If thisLabels(iLabel).ExtraValueLength(iValue) > 0 Then Put #hFile, , thisLabels(iLabel).ExtraValue(iValue)
End If
iValue = iValue + 1
Loop
Next iLabel
Close #hFile
End Sub
Private Function DecodeValue(ByVal sValue As String, Optional ByVal bToUnicode As Boolean = False) As String
'This works great, but what if it was supposed to be in unicode (e.g. Chinese?)
Dim iLoop As Long
Dim sText$, sConverted() As Byte
If bToUnicode Then
'string we want to encode is ANSI, so need to convert to unicode first
sValue = VBA.StrConv(sValue, vbUnicode)
End If
sText = sValue
sConverted = VBA.StrConv(sText, vbFromUnicode)
iLoop = Len(sValue) - 1
Do While iLoop <> -1
sConverted(iLoop) = Not sConverted(iLoop)
iLoop = iLoop - 1
Loop
DecodeValue = VBA.StrConv(sConverted, vbUnicode)
End Function
Public Function GetLang(Optional ByVal sLoadPath As String = "") As Long
Dim hFile As Integer
If Len(sLoadPath) <> 0 Then
If thisCSFPath <> sLoadPath Then
Call Initialise
thisCSFPath = sLoadPath
hFile = FreeFile()
Open thisCSFPath For Binary As #hFile
Get #hFile, , thisCSFHeader
Close #hFile
thisCSFPath = ""
End If
End If
If thisCSFHeader.HeaderID = " FSC" Then
If thisCSFHeader.Version = 3 Then
GetLang = thisCSFHeader.Language
Else
GetLang = -1
End If
Else
GetLang = -1
End If
End Function
Public Function LoadCSF(Optional ByVal sLoadPath As String = "") As Boolean
Dim hFile As Integer
Dim iLabel As Long
Dim iValue As Long
Dim sBuffer As String
LoadCSF = False
If Len(sLoadPath) <> 0 Then thisCSFPath = sLoadPath
hFile = FreeFile()
Open thisCSFPath For Binary As #hFile
Get #hFile, , thisCSFHeader
If thisCSFHeader.HeaderID = " FSC" Then
If thisCSFHeader.Version = 3 Then
ReDim thisLabels(thisCSFHeader.Labels + 500)
iLabel = 1
Do While iLabel <= thisCSFHeader.Labels
sBuffer = String$(4, " ")
Do While Not EOF(hFile)
Get #hFile, , sBuffer
If sBuffer = " LBL" Then Exit Do
Loop
Get #hFile, , thisLabels(iLabel).Substrings
Get #hFile, , thisLabels(iLabel).LabelNameLength
sBuffer = String$(thisLabels(iLabel).LabelNameLength, " ")
iValue = thisLabels(iLabel).Substrings
ReDim Preserve thisLabels(iLabel).ValueID(iValue)
ReDim Preserve thisLabels(iLabel).ValueLength(iValue)
ReDim Preserve thisLabels(iLabel).Value(iValue)
ReDim Preserve thisLabels(iLabel).ExtraValueLength(iValue)
ReDim Preserve thisLabels(iLabel).ExtraValue(iValue)
Get #hFile, , sBuffer
thisLabels(iLabel).LabelName = sBuffer
iValue = 1
Do While iValue <= thisLabels(iLabel).Substrings
Get #hFile, , thisLabels(iLabel).ValueID(iValue)
Select Case thisLabels(iLabel).ValueID(iValue)
Case " RTS", "WRTS"
'valid
Case Else
Exit Function
End Select
Get #hFile, , thisLabels(iLabel).ValueLength(iValue)
If thisLabels(iLabel).ValueLength(iValue) > 0 Then
sBuffer = String$(thisLabels(iLabel).ValueLength(iValue) * 2, " ")
Get #hFile, , sBuffer
thisLabels(iLabel).Value(iValue) = sBuffer
Else
thisLabels(iLabel).Value(iValue) = ""
End If
If thisLabels(iLabel).ValueID(iValue) = "WRTS" Then
Get #hFile, , thisLabels(iLabel).ExtraValueLength(iValue)
If thisLabels(iLabel).ExtraValueLength(iValue) > 0 Then
sBuffer = String$(thisLabels(iLabel).ExtraValueLength(iValue), " ")
Get #hFile, , sBuffer
thisLabels(iLabel).ExtraValue(iValue) = sBuffer
Else
thisLabels(iLabel).ExtraValue(iValue) = ""
End If
Else
thisLabels(iLabel).ExtraValueLength(iValue) = 0
thisLabels(iLabel).ExtraValue(iValue) = ""
End If
iValue = iValue + 1
Loop
iLabel = iLabel + 1
Loop
LoadCSF = True
'Else
'unsupported CSF version
End If
'Else
'not a CSF file
End If
Close #hFile
End Function
Public Sub AddLabel(ByVal sLabelName As String, ByVal sValue As String, Optional ByVal sExtraValue As String = "", Optional ByVal bANSI As Boolean = True, Optional ByVal bReplaceExisting As Boolean = True)
Dim iLabelNameLength
Dim iLabel As Long
Dim iValue As Long
sLabelName = LCase$(sLabelName)
iLabelNameLength = Len(sLabelName)
iLabel = 1
Do While iLabel <= thisCSFHeader.Labels
If thisLabels(iLabel).LabelNameLength = iLabelNameLength Then
If LCase$(thisLabels(iLabel).LabelName) = sLabelName Then Exit Do
End If
iLabel = iLabel + 1
Loop
If LCase$(thisLabels(iLabel).LabelName) <> sLabelName Or bReplaceExisting Then
If iLabel > thisCSFHeader.Labels Then
thisCSFHeader.Labels = iLabel
thisCSFHeader.ExtraValues = iLabel 'ra2md.csf has this set the same as label count, even though not every label has an extra value
If iLabel > UBound(thisLabels()) Then ReDim Preserve thisLabels(iLabel + 500)
thisLabels(iLabel).LabelName = sLabelName
thisLabels(iLabel).LabelNameLength = Len(sLabelName)
thisLabels(iLabel).Substrings = 1
End If
ReDim thisLabels(iLabel).ValueID(1)
ReDim thisLabels(iLabel).ValueLength(1)
ReDim thisLabels(iLabel).Value(1)
ReDim thisLabels(iLabel).ExtraValueLength(1)
ReDim thisLabels(iLabel).ExtraValue(1)
If Len(sExtraValue) = 0 Then
thisLabels(iLabel).ValueID(1) = " RTS"
thisLabels(iLabel).ExtraValueLength(1) = 0
thisLabels(iLabel).ExtraValue(1) = ""
Else
thisLabels(iLabel).ValueID(1) = "WRTS"
thisLabels(iLabel).ExtraValueLength(1) = Len(sExtraValue)
thisLabels(iLabel).ExtraValue(1) = sExtraValue
End If
If bANSI Then
thisLabels(iLabel).ValueLength(1) = Len(sValue)
Else
thisLabels(iLabel).ValueLength(1) = Len(sValue) / 2
End If
thisLabels(iLabel).Value(1) = DecodeValue(sValue, bANSI)
End If
End Sub
Public Sub UpdateWith(ByVal sFilePath As String, Optional ByVal bReplaceExisting As Boolean = True)
Dim secondCSF As MarshallxCSFClass
Dim iLabel As Long
Dim hFile As Integer
Dim sLabelValue As String
Dim bUnicode As Boolean
Dim sLabelName As String
Dim sBytes() As Byte
Dim sWord(1) As Byte
Dim iPos As Long
Dim iLen As Long
Dim bValueStage As Boolean
Select Case FileType(sFilePath)
Case "CSF"
Set secondCSF = New MarshallxCSFClass
Call secondCSF.LoadCSF(sFilePath)
iLabel = 1
Do While iLabel <= secondCSF.LabelCount
Call AddLabel(secondCSF.LabelName(iLabel), secondCSF.Value(iLabel), secondCSF.ExtraValue(iLabel), False, bReplaceExisting)
iLabel = iLabel + 1
Loop
Set secondCSF = Nothing
Case "TXT"
bUnicode = False
hFile = FreeFile()
Open sFilePath For Binary As #hFile
iLen = LOF(hFile)
If iLen >= 3 Then 'must have at least 3 characters to contain one label in ansi, and at least 2 bytes to identify a unicode file
iLen = iLen - 1 '(ubound of sbytes)
ReDim sBytes(iLen)
Get #hFile, , sBytes
If sBytes(0) = 255 And sBytes(1) = 254 Then 'HEX(FFFE) - the UTF-16 LE BOM
bUnicode = True
iPos = 2 'next byte to read
Else
bUnicode = False
iPos = 0 'next byte to read
End If
Close #hFile
sLabelValue = ""
sLabelName = ""
bValueStage = False
Do
If bUnicode Then
If iPos + 1 > iLen Then
'no more characters. see if we have a complete label
If bValueStage Then
If Len(sLabelName) <> 0 Then
Call AddLabel(sLabelName, sLabelValue, "", False, bReplaceExisting)
'else label name is blank (invalid)
End If
End If
Exit Do 'no more characters
End If
sWord(0) = sBytes(iPos)
sWord(1) = sBytes(iPos + 1)
iPos = iPos + 2
Else
If iPos > iLen Then
'no more characters. see if we have a complete label
If bValueStage Then
If Len(sLabelName) <> 0 Then
Call AddLabel(sLabelName, sLabelValue, "", False, bReplaceExisting)
'else label name is blank (invalid)
End If
End If
Exit Do 'no more characters
End If
sWord(0) = sBytes(iPos)
sWord(1) = 0
iPos = iPos + 1
End If
If sWord(1) = 0 Then
If Not bValueStage And sWord(0) = 61 Then '=
bValueStage = True
Else
Select Case sWord(0)
Case 13, 10 'CR, LF
If bValueStage Then
If Len(sLabelName) <> 0 Then
Call AddLabel(sLabelName, sLabelValue, "", False, bReplaceExisting)
'else label name is blank (invalid)
End If
'reset for next label
bValueStage = False
sLabelName = ""
sLabelValue = ""
End If
Case Else
If sWord(0) > 31 Or sWord(0) = 9 Then 'not a control char, unless its a tab
If Not bValueStage Then
'label name can't have spaces or tabs
If sWord(0) <> 32 And sWord(0) <> 9 Then '32=space, 9=tab
sLabelName = sLabelName & Chr(sWord(0))
End If
Else
If sWord(0) = 36 Then '$
'need to check if following characters are \n and replace with new line
If bUnicode Then
If (iPos + 2) < iLen Then
If sBytes(iPos) = 92 And sBytes(iPos + 1) = 0 And sBytes(iPos + 2) = 110 & sBytes(iPos + 3) = 0 Then '\n
sLabelValue = sLabelValue & Chr(13) & Chr(0)
sWord(0) = 10
iPos = iPos + 4
End If
End If
Else
If iPos < iLen Then
If sBytes(iPos) = 92 And sBytes(iPos + 1) = 110 Then '\n
sLabelValue = sLabelValue & Chr(13) & Chr(0)
sWord(0) = 10
iPos = iPos + 2
End If
End If
End If
End If
sLabelValue = sLabelValue & Chr(sWord(0)) & Chr(sWord(1))
End If
End If
End Select
End If
Else
If bValueStage Then sLabelValue = sLabelValue & Chr(sWord(0)) & Chr(sWord(1))
'else not valid - unicode chars not allowed in label name
End If
Loop
Else
Close #hFile
End If
End Select
End Sub