github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/cmd/rlpdump/main.go (about)

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