github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/cmd/rlpdump/main.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // Copyright 2019 The go-aigar Authors 3 // This file is part of the go-aigar library. 4 // 5 // The go-aigar library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-aigar library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>. 17 18 // rlpdump is a pretty-printer for RLP data. 19 package main 20 21 import ( 22 "bytes" 23 "encoding/hex" 24 "flag" 25 "fmt" 26 "io" 27 "os" 28 "strings" 29 30 "github.com/AigarNetwork/aigar/rlp" 31 ) 32 33 var ( 34 hexMode = flag.String("hex", "", "dump given hex data") 35 noASCII = flag.Bool("noascii", false, "don't print ASCII strings readably") 36 single = flag.Bool("single", false, "print only the first element, discard the rest") 37 ) 38 39 func init() { 40 flag.Usage = func() { 41 fmt.Fprintln(os.Stderr, "Usage:", os.Args[0], "[-noascii] [-hex <data>] [filename]") 42 flag.PrintDefaults() 43 fmt.Fprintln(os.Stderr, ` 44 Dumps RLP data from the given file in readable form. 45 If the filename is omitted, data is read from stdin.`) 46 } 47 } 48 49 func main() { 50 flag.Parse() 51 52 var r io.Reader 53 switch { 54 case *hexMode != "": 55 data, err := hex.DecodeString(strings.TrimPrefix(*hexMode, "0x")) 56 if err != nil { 57 die(err) 58 } 59 r = bytes.NewReader(data) 60 61 case flag.NArg() == 0: 62 r = os.Stdin 63 64 case flag.NArg() == 1: 65 fd, err := os.Open(flag.Arg(0)) 66 if err != nil { 67 die(err) 68 } 69 defer fd.Close() 70 r = fd 71 72 default: 73 fmt.Fprintln(os.Stderr, "Error: too many arguments") 74 flag.Usage() 75 os.Exit(2) 76 } 77 78 s := rlp.NewStream(r, 0) 79 for { 80 if err := dump(s, 0); err != nil { 81 if err != io.EOF { 82 die(err) 83 } 84 break 85 } 86 fmt.Println() 87 if *single { 88 break 89 } 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 }