github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/cmd/rlpdump/main.go (about)

     1  
     2  // rlpdump is a pretty-printer for RLP data.
     3  package main
     4  
     5  import (
     6  	"bytes"
     7  	"encoding/hex"
     8  	"flag"
     9  	"fmt"
    10  	"io"
    11  	"os"
    12  	"strings"
    13  
    14  	"github.com/quickchainproject/quickchain/rlp"
    15  )
    16  
    17  var (
    18  	hexMode = flag.String("hex", "", "dump given hex data")
    19  	noASCII = flag.Bool("noascii", false, "don't print ASCII strings readably")
    20  	single  = flag.Bool("single", false, "print only the first element, discard the rest")
    21  )
    22  
    23  func init() {
    24  	flag.Usage = func() {
    25  		fmt.Fprintln(os.Stderr, "Usage:", os.Args[0], "[-noascii] [-hex <data>] [filename]")
    26  		flag.PrintDefaults()
    27  		fmt.Fprintln(os.Stderr, `
    28  Dumps RLP data from the given file in readable form.
    29  If the filename is omitted, data is read from stdin.`)
    30  	}
    31  }
    32  
    33  func main() {
    34  	flag.Parse()
    35  
    36  	var r io.Reader
    37  	switch {
    38  	case *hexMode != "":
    39  		data, err := hex.DecodeString(strings.TrimPrefix(*hexMode, "0x"))
    40  		if err != nil {
    41  			die(err)
    42  		}
    43  		r = bytes.NewReader(data)
    44  
    45  	case flag.NArg() == 0:
    46  		r = os.Stdin
    47  
    48  	case flag.NArg() == 1:
    49  		fd, err := os.Open(flag.Arg(0))
    50  		if err != nil {
    51  			die(err)
    52  		}
    53  		defer fd.Close()
    54  		r = fd
    55  
    56  	default:
    57  		fmt.Fprintln(os.Stderr, "Error: too many arguments")
    58  		flag.Usage()
    59  		os.Exit(2)
    60  	}
    61  
    62  	s := rlp.NewStream(r, 0)
    63  	for {
    64  		if err := dump(s, 0); err != nil {
    65  			if err != io.EOF {
    66  				die(err)
    67  			}
    68  			break
    69  		}
    70  		fmt.Println()
    71  		if *single {
    72  			break
    73  		}
    74  	}
    75  }
    76  
    77  func dump(s *rlp.Stream, depth int) error {
    78  	kind, size, err := s.Kind()
    79  	if err != nil {
    80  		return err
    81  	}
    82  	switch kind {
    83  	case rlp.Byte, rlp.String:
    84  		str, err := s.Bytes()
    85  		if err != nil {
    86  			return err
    87  		}
    88  		if len(str) == 0 || !*noASCII && isASCII(str) {
    89  			fmt.Printf("%s%q", ws(depth), str)
    90  		} else {
    91  			fmt.Printf("%s%x", ws(depth), str)
    92  		}
    93  	case rlp.List:
    94  		s.List()
    95  		defer s.ListEnd()
    96  		if size == 0 {
    97  			fmt.Print(ws(depth) + "[]")
    98  		} else {
    99  			fmt.Println(ws(depth) + "[")
   100  			for i := 0; ; i++ {
   101  				if i > 0 {
   102  					fmt.Print(",\n")
   103  				}
   104  				if err := dump(s, depth+1); err == rlp.EOL {
   105  					break
   106  				} else if err != nil {
   107  					return err
   108  				}
   109  			}
   110  			fmt.Print(ws(depth) + "]")
   111  		}
   112  	}
   113  	return nil
   114  }
   115  
   116  func isASCII(b []byte) bool {
   117  	for _, c := range b {
   118  		if c < 32 || c > 126 {
   119  			return false
   120  		}
   121  	}
   122  	return true
   123  }
   124  
   125  func ws(n int) string {
   126  	return strings.Repeat("  ", n)
   127  }
   128  
   129  func die(args ...interface{}) {
   130  	fmt.Fprintln(os.Stderr, args...)
   131  	os.Exit(1)
   132  }