詳細代碼:https://github.com/cxcn/dtool
前言
微軟拼音和微軟五筆通用的用戶自定義短語 dat 格式,
決議
前 8 個位元組標識檔案格式 machxudp,微軟五筆的 lex 格式是 imscwubi,
下面 8 個位元組應該是版本號,
接下來每 4 位元組一組,分別表示偏移表開始、詞條開始、檔案總長、詞條數、匯出的時間戳,
然后補 0 一直到偏移表開始,
偏移表記錄了每個詞條從詞條開始的偏移量,每 4 個位元組一組,
接下來就是詞條本體部分:
| # | 占用位元組數 | 描述 |
|---|---|---|
| 4 | 10 00 10 00 標記 |
|
| a | 2 | 該詞條總位元組長 - 詞占用的位元組長 |
| 1 | 在候選中的位置 | |
| 1 | 0x06或0x13,未知 |
|
| 4 | 0 | |
| 4 | 從2010-01-01開始的時間戳 |
|
| a - 16 | 編碼(utf-16le),00 標識結束 | |
| 詞條總位元組長 - a | 詞(utf-16le),00 標識結束 |
代碼實作:
func (MsUDP) Parse(filename string) Table {
data, _ := os.ReadFile(filename)
r := bytes.NewReader(data)
ret := make(Table, 0, r.Len()>>8)
// 詞庫偏移量
r.Seek(0x10, 0)
offset_start := ReadUint32(r) // 偏移表開始
entry_start := ReadUint32(r) // 詞條開始
entry_end := ReadUint32(r) // 詞條結束
entry_count := ReadUint32(r) // 詞條數
export_time := ReadUint32(r) // 匯出的時間
t := time.Unix(int64(export_time), 0)
fmt.Println(t, entry_end)
// 第一個偏移量
offset := 0
for i := 0; i < entry_count; i++ {
var next, length int
if i == entry_count-1 {
length = entry_end - entry_start - offset
} else {
r.Seek(int64(offset_start+4*(i+1)), 0)
next = ReadUint32(r)
length = next - offset
}
// fmt.Println(offset, next, length)
r.Seek(int64(offset+entry_start), 0)
offset = next
ReadUint32(r) // 0x10001000
codeLen := ReadUint16(r) // 編碼位元組長+0x12
order, _ := r.ReadByte() // 順序
_, _ = r.ReadByte() // 0x06 不明
ReadUint32(r) // 4 個空位元組
ReadUint32(r) // 時間戳
tmp := make([]byte, codeLen-0x12)
r.Read(tmp)
code, _ := util.Decode(tmp, "UTF-16LE")
ReadUint16(r) // 兩個空位元組
tmp = make([]byte, length-codeLen-2)
r.Read(tmp)
word, _ := util.Decode(tmp, "UTF-16LE")
fmt.Println(code, word)
ret = append(ret, Entry{word, code, order})
}
return ret
}
生成
只需注意檔案總長先用空位元組代替,最后才寫入,
代碼實作:
func (MsUDP) Gen(table Table) []byte {
var buf bytes.Buffer
stamp := util.GetUint32(int(time.Now().Unix()))
buf.Write([]byte{0x6D, 0x73, 0x63, 0x68, 0x78, 0x75, 0x64, 0x70,
0x02, 0x00, 0x60, 0x00, 0x01, 0x00, 0x00, 0x00})
buf.Write(util.GetUint32(0x40))
buf.Write(util.GetUint32(0x40 + 4*len(table)))
buf.Write(make([]byte, 4)) // 待定 檔案總長
buf.Write(util.GetUint32(len(table)))
buf.Write(stamp)
buf.Write(make([]byte, 28))
buf.Write(make([]byte, 4))
words := make([][]byte, 0, len(table))
codes := make([][]byte, 0, len(table))
sum := 0
for i := range table {
word, _ := util.Encode([]byte(table[i].Word), "UTF-16LE")
code, _ := util.Encode([]byte(table[i].Code), "UTF-16LE")
words = append(words, word)
codes = append(codes, code)
if i != len(table)-1 {
sum += len(word) + len(code) + 20
buf.Write(util.GetUint32(sum))
}
}
for i := range table {
buf.Write([]byte{0x10, 0x00, 0x10, 0x00})
// fmt.Println(words[i], len(words[i]), codes[i], len(codes[i]))
buf.Write(util.GetUint16(len(codes[i]) + 18))
buf.WriteByte(table[i].Order)
buf.WriteByte(0x06)
buf.Write(make([]byte, 4))
buf.Write(stamp)
buf.Write(codes[i])
buf.Write([]byte{0, 0})
buf.Write(words[i])
buf.Write([]byte{0, 0})
}
b := buf.Bytes()
copy(b[0x18:0x1c], util.GetUint32(len(b)))
return b
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/508952.html
標籤:其他
