详细代码:https://github.com/cxcn/dtool

前言

微软拼音和微软五笔通用的用户自定义短语 dat 格式。

解析

前 8 个字节标识文件格式 machxudp,微软五笔的 lex 格式是 imscwubi

下面 8 个字节应该是版本号。

接下来每 4 字节一组,分别表示偏移表开始词条开始文件总长词条数导出的时间戳

然后补 0 一直到偏移表开始

偏移表记录了每个词条从词条开始的偏移量,每 4 个字节一组。

接下来就是词条本体部分:

# 占用字节数 描述
4 10 00 10 00 标记
a 2 该词条总字节长 - 词占用的字节长
1 在候选中的位置
1 0x060x13,未知
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
}

最新文章

  1. oracle11g 修改字符集
  2. 尝试在tensorflow上运行facenet
  3. 安卓开发-See the log file\.metadata\.log.
  4. CCF真题之数字排序
  5. 怎样查看oracle当前的连接数
  6. JavaScript - 测试 jQuery
  7. 读书笔记:java特种兵(上)
  8. 20151214--JSTL
  9. java调用(axis2)WebService传递对象类型参数(源码)
  10. R语言包下载(转载)
  11. LogCook 一个简单实用的Android日志管理工具
  12. Iview的开发之路
  13. Emacs 中 GDB 的使用
  14. 【精】EOS智能合约:system系统合约源码分析
  15. tomcat设置默认启动项
  16. codeforces 494a//Treasure// Codeforces Round #282(Div. 1)
  17. Ansible playbooks
  18. Mycat问题总结
  19. Django提示Unknown database处理方法
  20. codeforces VK Cup 2015 - Qualification Round 1 B. Photo to Remember 水题

热门文章

  1. NC14583 糖糖别胡说,我真的不是签到题目
  2. kubectl 最新常用命令 --V1.24版本
  3. 【cartogarpher_ros】三: 发布和订阅雷达scan信息
  4. Tomcat深入浅出——Session与Cookie(四)
  5. Unity-2D像素晶格化消融
  6. S32K148_CAN驱动(裸机开发)
  7. SQL语句的整合
  8. tokitsukaze and Soldier 来源:牛客网
  9. python opencv图像识别(相同大小图片)
  10. python在管道中执行命令