18
18
package main
19
19
20
20
import (
21
+ "bufio"
21
22
"bytes"
23
+ "container/list"
22
24
"encoding/hex"
23
25
"flag"
24
26
"fmt"
25
27
"io"
26
28
"os"
27
29
"strings"
28
30
31
+ "github.com/ethereum/go-ethereum/common"
29
32
"github.com/ethereum/go-ethereum/rlp"
30
33
)
31
34
32
35
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
+ hexMode = flag .String ("hex" , "" , "dump given hex data" )
37
+ reverseMode = flag .Bool ("reverse" , false , "convert ASCII to rlp" )
38
+ noASCII = flag .Bool ("noascii" , false , "don't print ASCII strings readably" )
39
+ single = flag .Bool ("single" , false , "print only the first element, discard the rest" )
36
40
)
37
41
38
42
func init () {
39
43
flag .Usage = func () {
40
- fmt .Fprintln (os .Stderr , "Usage:" , os .Args [0 ], "[-noascii] [-hex <data>] [filename]" )
44
+ fmt .Fprintln (os .Stderr , "Usage:" , os .Args [0 ], "[-noascii] [-hex <data>][-reverse] [filename]" )
41
45
flag .PrintDefaults ()
42
46
fmt .Fprintln (os .Stderr , `
43
47
Dumps RLP data from the given file in readable form.
@@ -73,23 +77,40 @@ func main() {
73
77
flag .Usage ()
74
78
os .Exit (2 )
75
79
}
80
+ out := os .Stdout
81
+ if * reverseMode {
82
+ data , err := textToRlp (r )
83
+ if err != nil {
84
+ die (err )
85
+ }
86
+ fmt .Printf ("0x%x\n " , data )
87
+ return
88
+ } else {
89
+ err := rlpToText (r , out )
90
+ if err != nil {
91
+ die (err )
92
+ }
93
+ }
94
+ }
76
95
96
+ func rlpToText (r io.Reader , out io.Writer ) error {
77
97
s := rlp .NewStream (r , 0 )
78
98
for {
79
- if err := dump (s , 0 ); err != nil {
99
+ if err := dump (s , 0 , out ); err != nil {
80
100
if err != io .EOF {
81
- die ( err )
101
+ return err
82
102
}
83
103
break
84
104
}
85
- fmt .Println ( )
105
+ fmt .Fprintln ( out )
86
106
if * single {
87
107
break
88
108
}
89
109
}
110
+ return nil
90
111
}
91
112
92
- func dump (s * rlp.Stream , depth int ) error {
113
+ func dump (s * rlp.Stream , depth int , out io. Writer ) error {
93
114
kind , size , err := s .Kind ()
94
115
if err != nil {
95
116
return err
@@ -101,28 +122,28 @@ func dump(s *rlp.Stream, depth int) error {
101
122
return err
102
123
}
103
124
if len (str ) == 0 || ! * noASCII && isASCII (str ) {
104
- fmt .Printf ( "%s%q" , ws (depth ), str )
125
+ fmt .Fprintf ( out , "%s%q" , ws (depth ), str )
105
126
} else {
106
- fmt .Printf ( "%s%x" , ws (depth ), str )
127
+ fmt .Fprintf ( out , "%s%x" , ws (depth ), str )
107
128
}
108
129
case rlp .List :
109
130
s .List ()
110
131
defer s .ListEnd ()
111
132
if size == 0 {
112
- fmt .Print ( ws (depth ) + "[]" )
133
+ fmt .Fprintf ( out , ws (depth )+ "[]" )
113
134
} else {
114
- fmt .Println ( ws (depth ) + "[" )
135
+ fmt .Fprintln ( out , ws (depth )+ "[" )
115
136
for i := 0 ; ; i ++ {
116
137
if i > 0 {
117
- fmt .Print ( ",\n " )
138
+ fmt .Fprint ( out , ",\n " )
118
139
}
119
- if err := dump (s , depth + 1 ); err == rlp .EOL {
140
+ if err := dump (s , depth + 1 , out ); err == rlp .EOL {
120
141
break
121
142
} else if err != nil {
122
143
return err
123
144
}
124
145
}
125
- fmt .Print ( ws (depth ) + "]" )
146
+ fmt .Fprint ( out , ws (depth )+ "]" )
126
147
}
127
148
}
128
149
return nil
@@ -145,3 +166,45 @@ func die(args ...interface{}) {
145
166
fmt .Fprintln (os .Stderr , args ... )
146
167
os .Exit (1 )
147
168
}
169
+
170
+ // textToRlp converts text into RLP (best effort).
171
+ func textToRlp (r io.Reader ) ([]byte , error ) {
172
+ // We're expecting the input to be well-formed, meaning that
173
+ // - each element is on a separate line
174
+ // - each line is either an (element OR a list start/end) + comma
175
+ // - an element is either hex-encoded bytes OR a quoted string
176
+ var (
177
+ scanner = bufio .NewScanner (r )
178
+ obj []interface {}
179
+ stack = list .New ()
180
+ )
181
+ for scanner .Scan () {
182
+ t := strings .TrimSpace (scanner .Text ())
183
+ if len (t ) == 0 {
184
+ continue
185
+ }
186
+ switch t {
187
+ case "[" : // list start
188
+ stack .PushFront (obj )
189
+ obj = make ([]interface {}, 0 )
190
+ case "]" , "]," : // list end
191
+ parent := stack .Remove (stack .Front ()).([]interface {})
192
+ obj = append (parent , obj )
193
+ case "[]," : // empty list
194
+ obj = append (obj , make ([]interface {}, 0 ))
195
+ default : // element
196
+ data := []byte (t )[:len (t )- 1 ] // cut off comma
197
+ if data [0 ] == '"' { // ascii string
198
+ data = []byte (t )[1 : len (data )- 1 ]
199
+ } else { // hex data
200
+ data = common .FromHex (string (data ))
201
+ }
202
+ obj = append (obj , data )
203
+ }
204
+ }
205
+ if err := scanner .Err (); err != nil {
206
+ return nil , err
207
+ }
208
+ data , err := rlp .EncodeToBytes (obj [0 ])
209
+ return data , err
210
+ }
0 commit comments