mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 07:32:32 +01:00
UTF8ToSJIS panicked when encountering characters outside the Shift-JIS range (emoji, Lenny faces, cuneiform, etc.), crashing the server when such characters were sent via the Discord relay channel. Replace the panic with graceful filtering that drops unmappable runes and preserves valid content. Also fix ToNGWord index-out-of-range panic on empty encoder output. Closes #116
146 lines
2.7 KiB
Go
146 lines
2.7 KiB
Go
package stringsupport
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"golang.org/x/text/encoding/japanese"
|
|
"golang.org/x/text/transform"
|
|
)
|
|
|
|
func UTF8ToSJIS(x string) []byte {
|
|
e := japanese.ShiftJIS.NewEncoder()
|
|
xt, _, err := transform.String(e, x)
|
|
if err != nil {
|
|
// Filter out runes that can't be encoded to Shift-JIS instead of
|
|
// crashing the server (see PR #116).
|
|
var filtered []rune
|
|
for _, r := range x {
|
|
if _, _, err := transform.String(japanese.ShiftJIS.NewEncoder(), string(r)); err == nil {
|
|
filtered = append(filtered, r)
|
|
}
|
|
}
|
|
xt, _, _ = transform.String(japanese.ShiftJIS.NewEncoder(), string(filtered))
|
|
}
|
|
return []byte(xt)
|
|
}
|
|
|
|
func SJISToUTF8(b []byte) string {
|
|
d := japanese.ShiftJIS.NewDecoder()
|
|
result, err := io.ReadAll(transform.NewReader(bytes.NewReader(b), d))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return string(result)
|
|
}
|
|
|
|
func ToNGWord(x string) []uint16 {
|
|
var w []uint16
|
|
for _, r := range x {
|
|
if r > 0xFF {
|
|
t := UTF8ToSJIS(string(r))
|
|
if len(t) > 1 {
|
|
w = append(w, uint16(t[1])<<8|uint16(t[0]))
|
|
} else if len(t) == 1 {
|
|
w = append(w, uint16(t[0]))
|
|
}
|
|
// Skip runes that produced no SJIS output (unsupported characters)
|
|
} else {
|
|
w = append(w, uint16(r))
|
|
}
|
|
}
|
|
return w
|
|
}
|
|
|
|
func PaddedString(x string, size uint, t bool) []byte {
|
|
if t {
|
|
e := japanese.ShiftJIS.NewEncoder()
|
|
xt, _, err := transform.String(e, x)
|
|
if err != nil {
|
|
return make([]byte, size)
|
|
}
|
|
x = xt
|
|
}
|
|
out := make([]byte, size)
|
|
copy(out, x)
|
|
out[len(out)-1] = 0
|
|
return out
|
|
}
|
|
|
|
func CSVAdd(csv string, v int) string {
|
|
if len(csv) == 0 {
|
|
return strconv.Itoa(v)
|
|
}
|
|
if CSVContains(csv, v) {
|
|
return csv
|
|
} else {
|
|
return csv + "," + strconv.Itoa(v)
|
|
}
|
|
}
|
|
|
|
func CSVRemove(csv string, v int) string {
|
|
s := strings.Split(csv, ",")
|
|
for i, e := range s {
|
|
if e == strconv.Itoa(v) {
|
|
s[i] = s[len(s)-1]
|
|
s = s[:len(s)-1]
|
|
}
|
|
}
|
|
return strings.Join(s, ",")
|
|
}
|
|
|
|
func CSVContains(csv string, v int) bool {
|
|
s := strings.Split(csv, ",")
|
|
for i := 0; i < len(s); i++ {
|
|
j, _ := strconv.ParseInt(s[i], 10, 32)
|
|
if int(j) == v {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func CSVLength(csv string) int {
|
|
if csv == "" {
|
|
return 0
|
|
}
|
|
s := strings.Split(csv, ",")
|
|
return len(s)
|
|
}
|
|
|
|
func CSVElems(csv string) []int {
|
|
var r []int
|
|
if csv == "" {
|
|
return r
|
|
}
|
|
s := strings.Split(csv, ",")
|
|
for i := 0; i < len(s); i++ {
|
|
j, _ := strconv.ParseInt(s[i], 10, 32)
|
|
r = append(r, int(j))
|
|
}
|
|
return r
|
|
}
|
|
|
|
func CSVGetIndex(csv string, i int) int {
|
|
s := CSVElems(csv)
|
|
if i < len(s) {
|
|
return s[i]
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func CSVSetIndex(csv string, i int, v int) string {
|
|
s := CSVElems(csv)
|
|
if i < len(s) {
|
|
s[i] = v
|
|
}
|
|
var r []string
|
|
for j := 0; j < len(s); j++ {
|
|
r = append(r, fmt.Sprintf(`%d`, s[j]))
|
|
}
|
|
return strings.Join(r, ",")
|
|
}
|