github.com/oweisse/u-root@v0.0.0-20181109060735-d005ad25fef1/xcmds/ed/bin.go (about) 1 // Copyright 2012-2017 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "bytes" 9 "fmt" 10 "io" 11 "io/ioutil" 12 "reflect" 13 "strconv" 14 ) 15 16 type bin struct { 17 dot int 18 dirty bool 19 data []byte 20 } 21 22 func (f *bin) String() string { 23 return fmt.Sprintf("%d %v", f.dot, len(f.data)) 24 } 25 26 func (f *bin) Replace(n []byte, start, end int) (int, error) { 27 defer debug("Replace done: f %v", f) 28 if f.data != nil { 29 debug("replace: f %v start %v end %v", f, start, end) 30 pre := f.data[0:start] 31 post := f.data[end:] 32 debug("replace: pre is %v, post is %v\n", pre, post) 33 var b bytes.Buffer 34 b.Write(pre) 35 b.Write(n) 36 b.Write(post) 37 f.data = b.Bytes() 38 } else { 39 f.data = n 40 } 41 return len(n), nil 42 } 43 44 // Read reads strings from the file after . 45 // If there are lines already the new lines are inserted after '.' 46 // dot is unchanged. 47 func (f *bin) Read(r io.Reader, start, end int) (int, error) { 48 debug("Read: r %v, start %v end %v", r, start, end) 49 d, err := ioutil.ReadAll(r) 50 debug("ReadAll returns %v, %v", d, err) 51 if err != nil { 52 return -1, err 53 } 54 return f.Replace(d, start, end) 55 } 56 57 // Write writes the lines out from start to end, inclusive. 58 // dot is unchanged. 59 func (f *bin) Write(w io.Writer, start, end int) (int, error) { 60 if end < start || start < 0 || end > len(f.data) { 61 return -1, fmt.Errorf("file is %d lines and [start, end] is [%d, %d]", len(f.data), start, end) 62 } 63 64 amt, err := w.Write(f.data[start:end]) 65 66 return amt, err 67 } 68 69 func (f *bin) Print(w io.Writer, start, end int) (int, error) { 70 if end > len(f.data) { 71 end = len(f.data) 72 } 73 for l := start; l < end; l += 16 { 74 fmt.Fprintf(w, "%08x ", l) 75 for b := l; b < end && b < l+16; b++ { 76 fmt.Fprintf(w, "%02x ", f.data[b]) 77 } 78 for b := l; b < end && b < l+16; b++ { 79 c := f.data[b] 80 if c < 32 || c > 126 { 81 fmt.Fprintf(w, ".") 82 } else { 83 fmt.Fprintf(w, "%c", c) 84 } 85 } 86 fmt.Printf("\n") 87 } 88 f.dot = end 89 return end - start, nil 90 } 91 92 // Sub replaces the regexp with a different one. 93 // I don't know how to do a regexp for bin. So, for now 94 // it's a simple substitution, and we'll start by assuming 95 // the same length 96 func (f *bin) Sub(x, y, opt string, start, end int) error { 97 debug("Slice from [%v,%v] %v", start, end, string(f.data[start:end])) 98 if len(x) != len(y) { 99 return fmt.Errorf("For now, old and new must be same len") 100 } 101 l := len(x) / 2 102 xb := make([]byte, l) 103 yb := make([]byte, l) 104 105 for i := range xb { 106 n := x[i*2 : i*2+2] 107 c, err := strconv.ParseUint(n, 16, 8) 108 if err != nil { 109 return fmt.Errorf("%s is not a hex number", n) 110 } 111 xb[i] = uint8(c) 112 n = y[i*2 : i*2+2] 113 c, err = strconv.ParseUint(n, 16, 8) 114 if err != nil { 115 return fmt.Errorf("%s is not a hex number", n) 116 } 117 yb[i] = uint8(c) 118 } 119 120 for i := start; i < end; i++ { 121 if reflect.DeepEqual(f.data[i:i+l], xb) { 122 copy(f.data[i:], yb) 123 } 124 } 125 return nil 126 } 127 128 func (f *bin) Dirty(d bool) { 129 f.dirty = d 130 } 131 132 func (f *bin) IsDirty() bool { 133 return f.dirty 134 } 135 136 func (f *bin) Range() (int, int) { 137 return 0, len(f.data) 138 } 139 140 func (f *bin) Equal(e Editor) error { 141 g := e.(*file) 142 // we should verify dot but let's not do that just yet, we don't 143 // have it right. 144 if /*f.dot != g.dot || */ !reflect.DeepEqual(f.data, g.data) { 145 return fmt.Errorf("%v is not the same as %v", f.String(), g.String()) 146 } 147 return nil 148 } 149 150 func (f *bin) Dot() int { 151 return f.dot 152 } 153 154 func (f *bin) Move(dot int) { 155 f.dot = dot 156 } 157 158 func NewBinEditor(a ...editorArg) (Editor, error) { 159 var f = &bin{} 160 for _, v := range a { 161 if err := v(f); err != nil { 162 return nil, err 163 } 164 } 165 f.dot = 0 166 return f, nil 167 }