Files
qgo-server/vendor/github.com/dunglas/httpsfv/displaystring.go
Smile Rex 6ace91a21a
All checks were successful
Create and publish a Docker image 🚀 / build-and-push-image (push) Successful in 1m49s
add vendor data
2026-03-10 01:11:41 +03:00

106 lines
2.0 KiB
Go

package httpsfv
import (
"encoding/hex"
"errors"
"strings"
"unicode"
"unicode/utf8"
)
type DisplayString string
var ErrInvalidDisplayString = errors.New("invalid display string type")
var notVcharOrSp = &unicode.RangeTable{
R16: []unicode.Range16{
{0x0000, 0x001f, 1},
{0x007f, 0x00ff, 1},
},
LatinOffset: 2,
}
// marshalSFV serializes as defined in
// https://httpwg.org/specs/rfc9651.html#ser-string.
func (s DisplayString) marshalSFV(b *strings.Builder) error {
if _, err := b.WriteString(`%"`); err != nil {
return err
}
for i := 0; i < len(s); i++ {
if s[i] == '%' || s[i] == '"' || unicode.Is(notVcharOrSp, rune(s[i])) {
b.WriteRune('%')
b.WriteString(hex.EncodeToString([]byte{s[i]}))
continue
}
b.WriteByte(s[i])
}
b.WriteByte('"')
return nil
}
// parseDisplayString parses as defined in
// https://httpwg.org/specs/rfc9651.html#parse-display.
func parseDisplayString(s *scanner) (DisplayString, error) {
if s.eof() || len(s.data[s.off:]) < 2 || s.data[s.off:2] != `%"` {
return "", &UnmarshalError{s.off, ErrInvalidDisplayString}
}
s.off += 2
var b strings.Builder
for !s.eof() {
c := s.data[s.off]
s.off++
switch c {
case '%':
if len(s.data[s.off:]) < 2 {
return "", &UnmarshalError{s.off, ErrInvalidDisplayString}
}
c0 := unhex(s.data[s.off])
if c0 == 0 {
return "", &UnmarshalError{s.off, ErrInvalidDisplayString}
}
c1 := unhex(s.data[s.off+1])
if c1 == 0 {
return "", &UnmarshalError{s.off, ErrInvalidDisplayString}
}
b.WriteByte(c0<<4 | c1)
s.off += 2
case '"':
r := b.String()
if !utf8.ValidString(r) {
return "", ErrInvalidDisplayString
}
return DisplayString(r), nil
default:
if unicode.Is(notVcharOrSp, rune(c)) {
return "", &UnmarshalError{s.off, ErrInvalidDisplayString}
}
b.WriteByte(c)
}
}
return "", &UnmarshalError{s.off, ErrInvalidDisplayString}
}
func unhex(c byte) byte {
switch {
case '0' <= c && c <= '9':
return c - '0'
case 'a' <= c && c <= 'f':
return c - 'a' + 10
default:
return 0
}
}