github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/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/ethereumproject/go-ethereum/rlp"
    30  )
    31  
    32  // Version is the application revision identifier. It can be set with the linker
    33  // as in: go build -ldflags "-X main.Version="`git describe --tags`
    34  var Version = "unknown"
    35  
    36  var (
    37  	hexMode     = flag.String("hex", "", "dump given hex data")
    38  	noASCII     = flag.Bool("noascii", false, "don't print ASCII strings readably")
    39  	versionFlag = flag.Bool("version", false, "Prints the revision identifier and exit immediatily.")
    40  )
    41  
    42  func init() {
    43  	flag.Usage = func() {
    44  		fmt.Fprintln(os.Stderr, "Usage:", os.Args[0], "[-noascii] [-hex <data>] [filename]")
    45  		flag.PrintDefaults()
    46  		fmt.Fprintln(os.Stderr, `
    47  Dumps RLP data from the given file in readable form.
    48  If the filename is omitted, data is read from stdin.`)
    49  	}
    50  }
    51  
    52  func main() {
    53  	flag.Parse()
    54  
    55  	if *versionFlag {
    56  		fmt.Println("rlpdump version", Version)
    57  		os.Exit(0)
    58  	}
    59  
    60  	var r io.Reader
    61  	switch {
    62  	case *hexMode != "":
    63  		data, err := hex.DecodeString(*hexMode)
    64  		if err != nil {
    65  			die(err)
    66  		}
    67  		r = bytes.NewReader(data)
    68  
    69  	case flag.NArg() == 0:
    70  		r = os.Stdin
    71  
    72  	case flag.NArg() == 1:
    73  		fd, err := os.Open(flag.Arg(0))
    74  		if err != nil {
    75  			die(err)
    76  		}
    77  		defer fd.Close()
    78  		r = fd
    79  
    80  	default:
    81  		fmt.Fprintln(os.Stderr, "Error: too many arguments")
    82  		flag.Usage()
    83  		os.Exit(2)
    84  	}
    85  
    86  	s := rlp.NewStream(r, 0)
    87  	for {
    88  		if err := dump(s, 0); err != nil {
    89  			if err != io.EOF {
    90  				die(err)
    91  			}
    92  			break
    93  		}
    94  		fmt.Println()
    95  	}
    96  }
    97  
    98  func dump(s *rlp.Stream, depth int) error {
    99  	kind, size, err := s.Kind()
   100  	if err != nil {
   101  		return err
   102  	}
   103  	switch kind {
   104  	case rlp.Byte, rlp.String:
   105  		str, err := s.Bytes()
   106  		if err != nil {
   107  			return err
   108  		}
   109  		if len(str) == 0 || !*noASCII && isASCII(str) {
   110  			fmt.Printf("%s%q", ws(depth), str)
   111  		} else {
   112  			fmt.Printf("%s%x", ws(depth), str)
   113  		}
   114  	case rlp.List:
   115  		s.List()
   116  		defer s.ListEnd()
   117  		if size == 0 {
   118  			fmt.Print(ws(depth) + "[]")
   119  		} else {
   120  			fmt.Println(ws(depth) + "[")
   121  			for i := 0; ; i++ {
   122  				if i > 0 {
   123  					fmt.Print(",\n")
   124  				}
   125  				if err := dump(s, depth+1); err == rlp.EOL {
   126  					break
   127  				} else if err != nil {
   128  					return err
   129  				}
   130  			}
   131  			fmt.Print(ws(depth) + "]")
   132  		}
   133  	}
   134  	return nil
   135  }
   136  
   137  func isASCII(b []byte) bool {
   138  	for _, c := range b {
   139  		if c < 32 || c > 126 {
   140  			return false
   141  		}
   142  	}
   143  	return true
   144  }
   145  
   146  func ws(n int) string {
   147  	return strings.Repeat("  ", n)
   148  }
   149  
   150  func die(args ...interface{}) {
   151  	fmt.Fprintln(os.Stderr, args...)
   152  	os.Exit(1)
   153  }