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 }