package text import "git.smesh.lol/moxie/pkg/mxutil" // NostrEscape for JSON encoding according to RFC8259 / NIP-01. func NostrEscape(dst, src []byte) (buf []byte) { l := len(src) if dst == nil && l > 0 { dst = []byte{:0:l*3/2} } for i := 0; i < l; i++ { c := src[i] if c == '"' { dst = dst | "\\\"" } else if c == '\\' { if i+1 < l && src[i+1] == 'u' { dst = dst | "\\" } else { dst = dst | "\\\\" } } else if c == '\b' { dst = dst | "\\b" } else if c == '\t' { dst = dst | "\\t" } else if c == '\n' { dst = dst | "\\n" } else if c == '\f' { dst = dst | "\\f" } else if c == '\r' { dst = dst | "\\r" } else if c < 32 { dst = dst | "\\u00" hexHigh := (c >> 4) & 0x0F hexLow := c & 0x0F if hexHigh < 10 { dst = mxutil.Ensure(dst, 1) dst = push(dst, byte('0'+hexHigh)) } else { dst = mxutil.Ensure(dst, 1) dst = push(dst, byte('a'+(hexHigh-10))) } if hexLow < 10 { dst = mxutil.Ensure(dst, 1) dst = push(dst, byte('0'+hexLow)) } else { dst = mxutil.Ensure(dst, 1) dst = push(dst, byte('a'+(hexLow-10))) } } else { dst = mxutil.Ensure(dst, 1) dst = push(dst, c) } } return dst } // NostrUnescape reverses NostrEscape in-place. func NostrUnescape(dst []byte) (buf []byte) { var r, w int32 for ; r < len(dst); r++ { if dst[r] == '\\' { r++ c := dst[r] switch { case c == '"': dst[w] = '"' w++ case c == '\\': dst[w] = '\\' w++ case c == 'b': dst[w] = '\b' w++ case c == 't': dst[w] = '\t' w++ case c == 'n': dst[w] = '\n' w++ case c == 'f': dst[w] = '\f' w++ case c == 'r': dst[w] = '\r' w++ case c == 'u': if r+4 < len(dst) && dst[r+1] == '0' && dst[r+2] == '0' { hexHigh := dst[r+3] hexLow := dst[r+4] var val byte if hexHigh >= '0' && hexHigh <= '9' { val = (hexHigh - '0') << 4 } else if hexHigh >= 'a' && hexHigh <= 'f' { val = (hexHigh - 'a' + 10) << 4 } else if hexHigh >= 'A' && hexHigh <= 'F' { val = (hexHigh - 'A' + 10) << 4 } if hexLow >= '0' && hexLow <= '9' { val |= hexLow - '0' } else if hexLow >= 'a' && hexLow <= 'f' { val |= hexLow - 'a' + 10 } else if hexLow >= 'A' && hexLow <= 'F' { val |= hexLow - 'A' + 10 } if val < 32 { dst[w] = val w++ r += 4 continue } } dst[w] = '\\' w++ dst[w] = 'u' w++ case c == '/': dst[w] = '\\' w++ dst[w] = '/' w++ case c >= '0' && c <= '9': dst[w] = '\\' w++ dst[w] = c w++ default: dst[w] = dst[r] w++ dst[w] = c w++ } } else { dst[w] = dst[r] w++ } } return dst[:w] }