接手《Quartett!》漢化專案,從 Script.dat 提取的腳本檔案命名為 MD5 雜湊值(如 0a69b4afebd6d64527a21e3f1aa993f9.tkn),內容為二進制格式。初步觀察發現:
TOKENSETd 特徵碼base_path、include、Script/BaseInstruction.txt、motion、Main0x00 結尾(C 風格),前導有一個高位元組(0x81、0x83、0x85 等)0x00,再前一個非零位元組尋找「三個 0x00 + 高位元組 (0x80-0x88) + C 字串」模式,提取:
0x1C 0x0C 0x81 base_path
0x2B 0x0C 0x83 ..
0x3B 0x16 0x81 include
0x48 0x16 0x83 Script/BaseInstruction.txt
0x68 0x20 0x81 motion
0x74 0x20 0x81 Main
發現「奇怪數字」(0x0C、0x16、0x20)遞增,推測為行號或 Token 索引。
加入 0x85(單字符運算子如 #),確認高位元組為 Token 類型標記:
| 值 | 類型 | 範例 |
|---|---|---|
| 0x80 | 十進制數字 | 123 |
| 0x81 | 識別符 | base_path, motion |
| 0x82 | 十六進制數字 | 0xFF |
| 0x83 | 字串字面值 | "../" |
| 0x85 | 運算子/符號 | #, {, }, (, ) |
特徵碼後 4 位元組(0x08 0x00 0x00 0x00 = 2048 = 0x800)非版本號,實為 Token 總數。修正掃描邏輯:依序讀取「行號 (int32) + 類型 (byte) + C 字串」重複 Token 總次數。
此「二進制腳本」實為 Scanner (Lexer) 輸出,保留完整 Token 序列(含行號、類型、原文),未經 Parser 語法分析。註解已被移除,空白行保留為行號間隔。
// 讀取 Token 總數
int tokenCount = reader.ReadInt32();
for (int i = 0; i < tokenCount; i++) {
int lineNum = reader.ReadInt32(); // 行號
TokenType type = (TokenType)reader.ReadByte(); // 類型
string text = ReadCString(reader); // 原文
// 處理換行與縮排
if (lastLineNum < lineNum) {
WriteEmptyLines(lastLineNum, lineNum);
WriteIndent(tabCount);
}
// 依類型格式化輸出
switch (type) {
case TokenType.String:
Write("\"" + text + "\"");
break;
case TokenType.Operator:
FormatOperator(text); // { 增加縮排、} 減少縮排、; 換行等
break;
default:
Write(text + (NeedSpaceBeforeNext(type) ? " " : ""));
}
lastLineNum = lineNum;
lastType = type;
}
{:輸出後增加縮排層級}:減少縮排、刪除前一個縮排、輸出; , ( =:後加空格):前加空格# % - @:直接輸出1.
2.
...
11. #base_path "../"
12.
...
21. #include "Script/BaseInstruction.txt"
22.
...
31. motion Main ( )
還原出近似原始碼結構,包含指令、引入、函式定義。空白行對應原始碼註解或空行位置。
分析工具原始碼以 BSD License 釋出,歡迎遵循授權條款自由使用、修改、散布。