github.com/mister-meeseeks/go-ethereum@v1.9.7/cmd/rlpdump/main.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // go-ethereum is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // rlpdump is a pretty-printer for RLP data.
    18  package main
    19  
    20  import (
    21  	"bytes"
    22  	"encoding/hex"
    23  	"flag"
    24  	"fmt"
    25  	"io"
    26  	"os"
    27  	"strings"
    28  
    29  	"github.com/ethereum/go-ethereum/rlp"
    30  )
    31  
    32  var (
    33  	hexMode = flag.String("hex", "", "dump given hex data")
    34  	noASCII = flag.Bool("noascii", false, "don't print ASCII strings readably")
    35  	single  = flag.Bool("single", false, "print only the first element, discard the rest")
    36  )
    37  
    38  func init() {
    39  	flag.Usage = func() {
    40  		fmt.Fprintln(os.Stderr, "Usage:", os.Args[0], "[-noascii] [-hex <data>] [filename]")
    41  		flag.PrintDefaults()
    42  		fmt.Fprintln(os.Stderr, `
    43  Dumps RLP data from the given file in readable form.
    44  If the filename is omitted, data is read from stdin.`)
    45  	}
    46  }
    47  
    48  func main() {
    49  	flag.Parse()
    50  
    51  	var r io.Reader
    52  	switch {
    53  	case *hexMode != "":
    54  		data, err := hex.DecodeString(strings.TrimPrefix(*hexMode, "0x"))
    55  		if err != nil {
    56  			die(err)
    57  		}
    58  		r = bytes.NewReader(data)
    59  
    60  	case flag.NArg() == 0:
    61  		r = os.Stdin
    62  
    63  	case flag.NArg() == 1:
    64  		fd, err := os.Open(flag.Arg(0))
    65  		if err != nil {
    66  			die(err)
    67  		}
    68  		defer fd.Close()
    69  		r = fd
    70  
    71  	default:
    72  		fmt.Fprintln(os.Stderr, "Error: too many arguments")
    73  		flag.Usage()
    74  		os.Exit(2)
    75  	}
    76  
    77  	s := rlp.NewStream(r, 0)
    78  	for {
    79  		if err := dump(s, 0); err != nil {
    80  			if err != io.EOF {
    81  				die(err)
    82  			}
    83  			break
    84  		}
    85  		fmt.Println()
    86  		if *single {
    87  			break
    88  		}
    89  	}
    90  }
    91  
    92  func dump(s *rlp.Stream, depth int) error {
    93  	kind, size, err := s.Kind()
    94  	if err != nil {
    95  		return err
    96  	}
    97  	switch kind {
    98  	case rlp.Byte, rlp.String:
    99  		str, err := s.Bytes()
   100  		if err != nil {
   101  			return err
   102  		}
   103  		if len(str) == 0 || !*noASCII && isASCII(str) {
   104  			fmt.Printf("%s%q", ws(depth), str)
   105  		} else {
   106  			fmt.Printf("%s%x", ws(depth), str)
   107  		}
   108  	case rlp.List:
   109  		s.List()
   110  		defer s.ListEnd()
   111  		if size == 0 {
   112  			fmt.Print(ws(depth) + "[]")
   113  		} else {
   114  			fmt.Println(ws(depth) + "[")
   115  			for i := 0; ; i++ {
   116  				if i > 0 {
   117  					fmt.Print(",\n")
   118  				}
   119  				if err := dump(s, depth+1); err == rlp.EOL {
   120  					break
   121  				} else if err != nil {
   122  					return err
   123  				}
   124  			}
   125  			fmt.Print(ws(depth) + "]")
   126  		}
   127  	}
   128  	return nil
   129  }
   130  
   131  func isASCII(b []byte) bool {
   132  	for _, c := range b {
   133  		if c < 32 || c > 126 {
   134  			return false
   135  		}
   136  	}
   137  	return true
   138  }
   139  
   140  func ws(n int) string {
   141  	return strings.Repeat("  ", n)
   142  }
   143  
   144  func die(args ...interface{}) {
   145  	fmt.Fprintln(os.Stderr, args...)
   146  	os.Exit(1)
   147  }