Files
rdplib/plugin/cliprdr/html_format.go
T

78 lines
2.4 KiB
Go

package cliprdr
import (
"fmt"
"strings"
)
// Windows "HTML Format" 剪贴板编解码(MS-Doc: HTML Clipboard Format)。
//
// 字节流 = 固定文本头 + HTML 文档。头共 5 行、每行 \r\n 结尾:
//
// Version:0.9\r\n (13 字节)
// StartHTML:0000000105\r\n (22 字节)
// EndHTML:0000000256\r\n (20 字节)
// StartFragment:0000000139\r\n (26 字节)
// EndFragment:0000000222\r\n (24 字节)
//
// 偏移为 10 位零填充的十进制**字节**偏移(UTF-8)。固定头总长 105 字节。
const cfHTMLHeaderLen = 13 + 22 + 20 + 26 + 24 // 105
const cfHTMLWrapPrefix = "<html><body><!--StartFragment-->"
const cfHTMLWrapSuffix = "<!--EndFragment--></body></html>"
// EncodeCFHTML 把 HTML 片段(fragment)包装成 "HTML Format" 剪贴板字节流。
func EncodeCFHTML(fragment string) []byte {
startHTML := cfHTMLHeaderLen
startFragment := startHTML + len(cfHTMLWrapPrefix)
endFragment := startFragment + len(fragment)
endHTML := endFragment + len(cfHTMLWrapSuffix)
head := fmt.Sprintf("Version:0.9\r\nStartHTML:%010d\r\nEndHTML:%010d\r\nStartFragment:%010d\r\nEndFragment:%010d\r\n",
startHTML, endHTML, startFragment, endFragment)
doc := cfHTMLWrapPrefix + fragment + cfHTMLWrapSuffix
return []byte(head + doc)
}
// DecodeCFHTML 从 "HTML Format" 剪贴板字节流中提取 StartFragment 到
// EndFragment 之间的 HTML 内容。头部解析失败时回退为整段字符串。
func DecodeCFHTML(data []byte) string {
s := string(data)
lines := strings.Split(s, "\r\n")
var startFragment, endFragment int = -1, -1
// 头最多 5 行;解析到两个 Fragment 偏移即可停止。
for i, ln := range lines {
if i >= 5 {
break
}
if v, ok := parseOffsetLine(ln, "StartFragment:"); ok {
startFragment = v
} else if v, ok := parseOffsetLine(ln, "EndFragment:"); ok {
endFragment = v
}
if startFragment >= 0 && endFragment > startFragment && endFragment <= len(data) {
break
}
}
if startFragment < 0 || endFragment <= startFragment || endFragment > len(data) {
// 回退:无有效偏移时原样返回(去除首行头部不可行,尽力而为)
return s
}
return s[startFragment:endFragment]
}
func parseOffsetLine(line, key string) (int, bool) {
if !strings.HasPrefix(line, key) {
return 0, false
}
v := 0
for _, c := range line[len(key):] {
if c < '0' || c > '9' {
return 0, false
}
v = v*10 + int(c-'0')
}
return v, true
}