github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/logql/log/logfmt/jsonstring.go (about)

     1  package logfmt
     2  
     3  import (
     4  	"strconv"
     5  	"unicode"
     6  	"unicode/utf16"
     7  	"unicode/utf8"
     8  )
     9  
    10  // Taken from Go's encoding/json and modified for use here.
    11  
    12  // Copyright 2010 The Go Authors. All rights reserved.
    13  // Use of this source code is governed by a BSD-style
    14  // license that can be found in the LICENSE file.
    15  
    16  func getu4(s []byte) rune {
    17  	if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
    18  		return -1
    19  	}
    20  	r, err := strconv.ParseUint(string(s[2:6]), 16, 64)
    21  	if err != nil {
    22  		return -1
    23  	}
    24  	return rune(r)
    25  }
    26  
    27  func unquoteBytes(s []byte) (t []byte, ok bool) {
    28  	if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
    29  		return
    30  	}
    31  	s = s[1 : len(s)-1]
    32  
    33  	// Check for unusual characters. If there are none,
    34  	// then no unquoting is needed, so return a slice of the
    35  	// original bytes.
    36  	r := 0
    37  	for r < len(s) {
    38  		c := s[r]
    39  		if c == '\\' || c == '"' {
    40  			break
    41  		}
    42  		if c < utf8.RuneSelf {
    43  			r++
    44  			continue
    45  		}
    46  		rr, size := utf8.DecodeRune(s[r:])
    47  		if rr == utf8.RuneError {
    48  			break
    49  		}
    50  		r += size
    51  	}
    52  	if r == len(s) {
    53  		return s, true
    54  	}
    55  
    56  	b := make([]byte, len(s)+2*utf8.UTFMax)
    57  	w := copy(b, s[0:r])
    58  	for r < len(s) {
    59  		// Out of room?  Can only happen if s is full of
    60  		// malformed UTF-8 and we're replacing each
    61  		// byte with RuneError.
    62  		if w >= len(b)-2*utf8.UTFMax {
    63  			nb := make([]byte, (len(b)+utf8.UTFMax)*2)
    64  			copy(nb, b[0:w])
    65  			b = nb
    66  		}
    67  		switch c := s[r]; {
    68  		case c == '\\':
    69  			r++
    70  			if r >= len(s) {
    71  				return
    72  			}
    73  			switch s[r] {
    74  			default:
    75  				return
    76  			case '"', '\\', '/', '\'':
    77  				b[w] = s[r]
    78  				r++
    79  				w++
    80  			case 'b':
    81  				b[w] = '\b'
    82  				r++
    83  				w++
    84  			case 'f':
    85  				b[w] = '\f'
    86  				r++
    87  				w++
    88  			case 'n':
    89  				b[w] = '\n'
    90  				r++
    91  				w++
    92  			case 'r':
    93  				b[w] = '\r'
    94  				r++
    95  				w++
    96  			case 't':
    97  				b[w] = '\t'
    98  				r++
    99  				w++
   100  			case 'u':
   101  				r--
   102  				rr := getu4(s[r:])
   103  				if rr < 0 {
   104  					return
   105  				}
   106  				r += 6
   107  				if utf16.IsSurrogate(rr) {
   108  					rr1 := getu4(s[r:])
   109  					if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar {
   110  						// A valid pair; consume.
   111  						r += 6
   112  						w += utf8.EncodeRune(b[w:], dec)
   113  						break
   114  					}
   115  					// Invalid surrogate; fall back to replacement rune.
   116  					rr = unicode.ReplacementChar
   117  				}
   118  				w += utf8.EncodeRune(b[w:], rr)
   119  			}
   120  
   121  		// Unescaped quote is invalid.
   122  		case c == '"':
   123  			return
   124  
   125  		// ASCII
   126  		case c < utf8.RuneSelf:
   127  			b[w] = c
   128  			r++
   129  			w++
   130  
   131  		// Coerce to well-formed UTF-8.
   132  		default:
   133  			rr, size := utf8.DecodeRune(s[r:])
   134  			r += size
   135  			w += utf8.EncodeRune(b[w:], rr)
   136  		}
   137  	}
   138  	return b[0:w], true
   139  }