Source file src/cmd/internal/objabi/path.go

     1  // Copyright 2017 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package objabi
     6  
     7  import (
     8  	"fmt"
     9  	"strconv"
    10  	"strings"
    11  )
    12  
    13  // PathToPrefix converts raw string to the prefix that will be used in the
    14  // symbol table. All control characters, space, '%' and '"', as well as
    15  // non-7-bit clean bytes turn into %xx. The period needs escaping only in the
    16  // last segment of the path, and it makes for happier users if we escape that as
    17  // little as possible.
    18  func PathToPrefix(s string) string {
    19  	slash := strings.LastIndex(s, "/")
    20  	// check for chars that need escaping
    21  	n := 0
    22  	for r := 0; r < len(s); r++ {
    23  		if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F {
    24  			n++
    25  		}
    26  	}
    27  
    28  	// quick exit
    29  	if n == 0 {
    30  		return s
    31  	}
    32  
    33  	// escape
    34  	const hex = "0123456789abcdef"
    35  	p := make([]byte, 0, len(s)+2*n)
    36  	for r := 0; r < len(s); r++ {
    37  		if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F {
    38  			p = append(p, '%', hex[c>>4], hex[c&0xF])
    39  		} else {
    40  			p = append(p, c)
    41  		}
    42  	}
    43  
    44  	return string(p)
    45  }
    46  
    47  // PrefixToPath is the inverse of PathToPrefix, replacing escape sequences with
    48  // the original character.
    49  func PrefixToPath(s string) (string, error) {
    50  	percent := strings.IndexByte(s, '%')
    51  	if percent == -1 {
    52  		return s, nil
    53  	}
    54  
    55  	p := make([]byte, 0, len(s))
    56  	for i := 0; i < len(s); {
    57  		if s[i] != '%' {
    58  			p = append(p, s[i])
    59  			i++
    60  			continue
    61  		}
    62  		if i+2 >= len(s) {
    63  			// Not enough characters remaining to be a valid escape
    64  			// sequence.
    65  			return "", fmt.Errorf("malformed prefix %q: escape sequence must contain two hex digits", s)
    66  		}
    67  
    68  		b, err := strconv.ParseUint(s[i+1:i+3], 16, 8)
    69  		if err != nil {
    70  			// Not a valid escape sequence.
    71  			return "", fmt.Errorf("malformed prefix %q: escape sequence %q must contain two hex digits", s, s[i:i+3])
    72  		}
    73  
    74  		p = append(p, byte(b))
    75  		i += 3
    76  	}
    77  	return string(p), nil
    78  }
    79  

View as plain text