78 lines
2.4 KiB
Go
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
|
|
}
|