github.com/jonasnick/go-ethereum@v0.7.12-0.20150216215225-22176f05d387/cmd/rlpdump/main.go (about) 1 /* 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 /** 18 * @authors 19 * Felix Lange <felix@ethdev.com> 20 */ 21 22 // rlpdump is a pretty-printer for RLP data. 23 package main 24 25 import ( 26 "bytes" 27 "encoding/hex" 28 "flag" 29 "fmt" 30 "io" 31 "os" 32 "strings" 33 34 "github.com/jonasnick/go-ethereum/rlp" 35 ) 36 37 var ( 38 hexMode = flag.String("hex", "", "dump given hex data") 39 noASCII = flag.Bool("noascii", false, "don't print ASCII strings readably") 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 var r io.Reader 56 switch { 57 case *hexMode != "": 58 data, err := hex.DecodeString(*hexMode) 59 if err != nil { 60 die(err) 61 } 62 r = bytes.NewReader(data) 63 64 case flag.NArg() == 0: 65 r = os.Stdin 66 67 case flag.NArg() == 1: 68 fd, err := os.Open(flag.Arg(0)) 69 if err != nil { 70 die(err) 71 } 72 defer fd.Close() 73 r = fd 74 75 default: 76 fmt.Fprintln(os.Stderr, "Error: too many arguments") 77 flag.Usage() 78 os.Exit(2) 79 } 80 81 s := rlp.NewStream(r) 82 for { 83 if err := dump(s, 0); err != nil { 84 if err != io.EOF { 85 die(err) 86 } 87 break 88 } 89 fmt.Println() 90 } 91 } 92 93 func dump(s *rlp.Stream, depth int) error { 94 kind, size, err := s.Kind() 95 if err != nil { 96 return err 97 } 98 switch kind { 99 case rlp.Byte, rlp.String: 100 str, err := s.Bytes() 101 if err != nil { 102 return err 103 } 104 if len(str) == 0 || !*noASCII && isASCII(str) { 105 fmt.Printf("%s%q", ws(depth), str) 106 } else { 107 fmt.Printf("%s%x", ws(depth), str) 108 } 109 case rlp.List: 110 s.List() 111 defer s.ListEnd() 112 if size == 0 { 113 fmt.Print(ws(depth) + "[]") 114 } else { 115 fmt.Println(ws(depth) + "[") 116 for i := 0; ; i++ { 117 if i > 0 { 118 fmt.Print(",\n") 119 } 120 if err := dump(s, depth+1); err == rlp.EOL { 121 break 122 } else if err != nil { 123 return err 124 } 125 } 126 fmt.Print(ws(depth) + "]") 127 } 128 } 129 return nil 130 } 131 132 func isASCII(b []byte) bool { 133 for _, c := range b { 134 if c < 32 || c > 126 { 135 return false 136 } 137 } 138 return true 139 } 140 141 func ws(n int) string { 142 return strings.Repeat(" ", n) 143 } 144 145 func die(args ...interface{}) { 146 fmt.Fprintln(os.Stderr, args...) 147 os.Exit(1) 148 }