package text // NostrEscape for JSON encoding according to RFC8259 / NIP-01. func NostrEscape(dst, src []byte) []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 = append(dst, '\\', '"') } else if c == '\\' { if i+1 < l && src[i+1] == 'u' { dst = append(dst, '\\') } else { dst = append(dst, '\\', '\\') } } else if c == '\b' { dst = append(dst, '\\', 'b') } else if c == '\t' { dst = append(dst, '\\', 't') } else if c == '\n' { dst = append(dst, '\\', 'n') } else if c == '\f' { dst = append(dst, '\\', 'f') } else if c == '\r' { dst = append(dst, '\\', 'r') } else if c < 32 { dst = append(dst, '\\', 'u', '0', '0') hexHigh := (c >> 4) & 0x0F hexLow := c & 0x0F if hexHigh < 10 { dst = append(dst, byte('0'+hexHigh)) } else { dst = append(dst, byte('a'+(hexHigh-10))) } if hexLow < 10 { dst = append(dst, byte('0'+hexLow)) } else { dst = append(dst, byte('a'+(hexLow-10))) } } else { dst = append(dst, c) } } return dst } // NostrUnescape reverses NostrEscape in-place. func NostrUnescape(dst []byte) []byte { var r, w int 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] }