Skip to content

Commit

Permalink
fix #1733
Browse files Browse the repository at this point in the history
  • Loading branch information
Mrs4s committed Dec 1, 2022
1 parent cdf7638 commit 0248c86
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 3 deletions.
4 changes: 2 additions & 2 deletions coolq/cqcode/element.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ package cqcode

import (
"bytes"
"strconv"
"strings"

"github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/go-cqhttp/global"
)

// Element single message
Expand Down Expand Up @@ -60,7 +60,7 @@ func (e *Element) MarshalJSON() ([]byte, error) {
buf.WriteByte('"')
buf.WriteString(data.K)
buf.WriteString(`":`)
buf.WriteString(strconv.Quote(data.V))
buf.WriteString(global.Quote(data.V))
}
buf.WriteString(`}}`)
}), nil
Expand Down
6 changes: 5 additions & 1 deletion coolq/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ func (ev *event) MarshalJSON() ([]byte, error) {
fmt.Fprintf(buf, `,"sub_type":"%s"`, ev.SubType)
}
for k, v := range ev.Others {
v, _ := json.Marshal(v)
v, err := json.Marshal(v)
if err != nil {
log.Warnf("marshal message payload error: %v", err)
return nil, err
}
fmt.Fprintf(buf, `,"%s":%s`, k, v)
}
buf.WriteByte('}')
Expand Down
146 changes: 146 additions & 0 deletions global/quote.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package global

import (
"strconv"
"unicode/utf8"
)

const (
lowerhex = "0123456789abcdef"
upperhex = "0123456789ABCDEF"
)

// Quote returns a double-quoted Go string literal representing s. The
// returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for
// control characters and non-printable characters as defined by
// IsPrint.
func Quote(s string) string {
return quoteWith(s, '"', false, false)
}

func quoteWith(s string, quote byte, ASCIIonly, graphicOnly bool) string {
return string(appendQuotedWith(make([]byte, 0, 3*len(s)/2), s, quote, ASCIIonly, graphicOnly))
}

func appendQuotedWith(buf []byte, s string, quote byte, ASCIIonly, graphicOnly bool) []byte {
// Often called with big strings, so preallocate. If there's quoting,
// this is conservative but still helps a lot.
if cap(buf)-len(buf) < len(s) {
nBuf := make([]byte, len(buf), len(buf)+1+len(s)+1)
copy(nBuf, buf)
buf = nBuf
}
buf = append(buf, quote)
for width := 0; len(s) > 0; s = s[width:] {
r := rune(s[0])
width = 1
if r >= utf8.RuneSelf {
r, width = utf8.DecodeRuneInString(s)
}
if width == 1 && r == utf8.RuneError {
buf = append(buf, `\x`...)
buf = append(buf, lowerhex[s[0]>>4])
buf = append(buf, lowerhex[s[0]&0xF])
continue
}
buf = appendEscapedRune(buf, r, quote, ASCIIonly, graphicOnly)
}
buf = append(buf, quote)
return buf
}
func appendEscapedRune(buf []byte, r rune, quote byte, ASCIIonly, graphicOnly bool) []byte {
var runeTmp [utf8.UTFMax]byte
if r == rune(quote) || r == '\\' { // always backslashed
buf = append(buf, '\\')
buf = append(buf, byte(r))
return buf
}
if ASCIIonly {
if r < utf8.RuneSelf && strconv.IsPrint(r) {
buf = append(buf, byte(r))
return buf
}
} else if strconv.IsPrint(r) || graphicOnly && isInGraphicList(r) {
n := utf8.EncodeRune(runeTmp[:], r)
buf = append(buf, runeTmp[:n]...)
return buf
}
switch r {
case '\a':
buf = append(buf, `\a`...)
case '\b':
buf = append(buf, `\b`...)
case '\f':
buf = append(buf, `\f`...)
case '\n':
buf = append(buf, `\n`...)
case '\r':
buf = append(buf, `\r`...)
case '\t':
buf = append(buf, `\t`...)
case '\v':
buf = append(buf, `\v`...)
default:
switch {
case !utf8.ValidRune(r):
r = 0xFFFD
fallthrough
case r < 0x10000:
buf = append(buf, `\u`...)
for s := 12; s >= 0; s -= 4 {
buf = append(buf, lowerhex[r>>uint(s)&0xF])
}
default:
buf = append(buf, `\U`...)
for s := 28; s >= 0; s -= 4 {
buf = append(buf, lowerhex[r>>uint(s)&0xF])
}
}
}
return buf
}

func isInGraphicList(r rune) bool {
// We know r must fit in 16 bits - see makeisprint.go.
if r > 0xFFFF {
return false
}
rr := uint16(r)
i := bsearch16(isGraphic, rr)
return i < len(isGraphic) && rr == isGraphic[i]
}

// bsearch16 returns the smallest i such that a[i] >= x.
// If there is no such i, bsearch16 returns len(a).
func bsearch16(a []uint16, x uint16) int {
i, j := 0, len(a)
for i < j {
h := i + (j-i)>>1
if a[h] < x {
i = h + 1
} else {
j = h
}
}
return i
}

// isGraphic lists the graphic runes not matched by IsPrint.
var isGraphic = []uint16{
0x00a0,
0x1680,
0x2000,
0x2001,
0x2002,
0x2003,
0x2004,
0x2005,
0x2006,
0x2007,
0x2008,
0x2009,
0x200a,
0x202f,
0x205f,
0x3000,
}

0 comments on commit 0248c86

Please sign in to comment.