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  }