gohex.go raw

   1  package gohex
   2  
   3  import (
   4  	"bufio"
   5  	"encoding/hex"
   6  	"io"
   7  	"sort"
   8  )
   9  
  10  // Constants definitions of IntelHex record types
  11  const (
  12  	_DATA_RECORD   byte = 0 // Record with data bytes
  13  	_EOF_RECORD    byte = 1 // Record with end of file indicator
  14  	_ADR_20_RECORD byte = 2 // Record with extended 20-bit linear address
  15  	_ADR_32_RECORD byte = 4 // Record with extended 32-bit linear address
  16  	_START_RECORD  byte = 5 // Record with start linear address
  17  )
  18  
  19  // Structure with binary data segment fields
  20  type DataSegment struct {
  21  	Address uint32 // Starting address of data segment
  22  	Data    []byte // Data segment bytes
  23  }
  24  
  25  // Helper type for data segments sorting operations
  26  type sortByAddress []*DataSegment
  27  
  28  func (segs sortByAddress) Len() int           { return len(segs) }
  29  func (segs sortByAddress) Swap(i, j int)      { segs[i], segs[j] = segs[j], segs[i] }
  30  func (segs sortByAddress) Less(i, j int) bool { return segs[i].Address < segs[j].Address }
  31  
  32  // Main structure with private fields of IntelHex parser
  33  type Memory struct {
  34  	dataSegments     []*DataSegment // Slice with pointers to DataSegments
  35  	startAddress     uint32         // Start linear address
  36  	extendedAddress  uint32         // Extended linear address
  37  	eofFlag          bool           // End of file record exist flag
  38  	startFlag        bool           // Start address record exist flag
  39  	lineNum          uint           // Parser input line number
  40  	firstAddressFlag bool           // Dump first address line
  41  }
  42  
  43  // Constructor of Memory structure
  44  func NewMemory() *Memory {
  45  	m := new(Memory)
  46  	m.Clear()
  47  	return m
  48  }
  49  
  50  // Method to getting start address from IntelHex data
  51  func (m *Memory) GetStartAddress() (adr uint32, ok bool) {
  52  	if m.startFlag {
  53  		return m.startAddress, true
  54  	}
  55  	return 0, false
  56  }
  57  
  58  // Method to setting start address to IntelHex data
  59  func (m *Memory) SetStartAddress(adr uint32) {
  60  	m.startAddress = adr
  61  	m.startFlag = true
  62  }
  63  
  64  // Method to getting data segments address from IntelHex data
  65  func (m *Memory) GetDataSegments() []DataSegment {
  66  	segs := []DataSegment{}
  67  	for _, s := range m.dataSegments {
  68  		segs = append(segs, *s)
  69  	}
  70  	return segs
  71  }
  72  
  73  // Method to clear memory structure
  74  func (m *Memory) Clear() {
  75  	m.startAddress = 0
  76  	m.extendedAddress = 0
  77  	m.lineNum = 0
  78  	m.dataSegments = []*DataSegment{}
  79  	m.startFlag = false
  80  	m.eofFlag = false
  81  	m.firstAddressFlag = false
  82  }
  83  
  84  func (seg *DataSegment) isOverlap(adr uint32, size uint32) bool {
  85  	if ((adr >= seg.Address) && (adr < seg.Address+uint32(len(seg.Data)))) ||
  86  		((adr < seg.Address) && (adr+size) > seg.Address) {
  87  		return true
  88  	}
  89  	return false
  90  }
  91  
  92  func (m *Memory) removeSegment(index int) {
  93  	size := len(m.dataSegments)
  94  
  95  	if size == 0 {
  96  		return
  97  	} else if size == 1 {
  98  		m.dataSegments = []*DataSegment{}
  99  	} else {
 100  		if index == 0 {
 101  			m.dataSegments = m.dataSegments[1:]
 102  		} else if index == size-1 {
 103  			m.dataSegments = m.dataSegments[:index]
 104  		} else {
 105  			m.dataSegments = append(m.dataSegments[:index], m.dataSegments[index+1:]...)
 106  		}
 107  	}
 108  }
 109  
 110  func (m *Memory) findDataSegment(adr uint32) (seg *DataSegment, offset uint32, index int) {
 111  	for i, s := range m.dataSegments {
 112  		if s.isOverlap(adr, 1) == true {
 113  			return s, adr - s.Address, i
 114  		}
 115  	}
 116  	return nil, 0, 0
 117  }
 118  
 119  // Method to add binary data to memory (auto segmented and sorted)
 120  func (m *Memory) AddBinary(adr uint32, bytes []byte) error {
 121  	var segBefore *DataSegment = nil
 122  	var segAfter *DataSegment = nil
 123  	var segAfterIndex int
 124  	for i, s := range m.dataSegments {
 125  		if s.isOverlap(adr, uint32(len(bytes))) == true {
 126  			return newParseError(_DATA_ERROR, "data segments overlap", m.lineNum)
 127  		}
 128  
 129  		if adr == s.Address+uint32(len(s.Data)) {
 130  			segBefore = s
 131  		}
 132  		if adr+uint32(len(bytes)) == s.Address {
 133  			segAfter, segAfterIndex = s, i
 134  		}
 135  	}
 136  
 137  	if segBefore != nil && segAfter != nil {
 138  		segBefore.Data = append(segBefore.Data, bytes...)
 139  		segBefore.Data = append(segBefore.Data, segAfter.Data...)
 140  		m.dataSegments = append(m.dataSegments[:segAfterIndex], m.dataSegments[segAfterIndex+1:]...)
 141  
 142  	} else if segBefore != nil && segAfter == nil {
 143  		segBefore.Data = append(segBefore.Data, bytes...)
 144  	} else if segBefore == nil && segAfter != nil {
 145  		segAfter.Address = adr
 146  		segAfter.Data = append(bytes, segAfter.Data...)
 147  	} else {
 148  		data := make([]byte, len(bytes))
 149  		copy(data, bytes)
 150  		m.dataSegments = append(m.dataSegments, &DataSegment{Address: adr, Data: data})
 151  	}
 152  	sort.Sort(sortByAddress(m.dataSegments))
 153  	return nil
 154  }
 155  
 156  // Method to set binary data to memory (data overlapped will change, auto segmented and sorted)
 157  func (m *Memory) SetBinary(adr uint32, bytes []byte) {
 158  	for a, b := range bytes {
 159  		currentAdr := adr + uint32(a)
 160  		seg, offset, _ := m.findDataSegment(currentAdr)
 161  
 162  		if seg != nil {
 163  			seg.Data[offset] = b
 164  		} else {
 165  			m.AddBinary(currentAdr, []byte{b})
 166  		}
 167  	}
 168  }
 169  
 170  // Method to remove binary data from memory (auto segmented and sorted)
 171  func (m *Memory) RemoveBinary(adr uint32, size uint32) {
 172  	adrEnd := adr + size
 173  	for currentAdr := adr; currentAdr < adrEnd; currentAdr++ {
 174  		seg, offset, index := m.findDataSegment(currentAdr)
 175  
 176  		if seg == nil {
 177  			continue
 178  		}
 179  
 180  		if offset == 0 {
 181  			seg.Address += 1
 182  			if len(seg.Data) > 1 {
 183  				seg.Data = seg.Data[1:]
 184  			} else {
 185  				m.removeSegment(index)
 186  			}
 187  		} else if offset == uint32(len(seg.Data)-1) {
 188  			if len(seg.Data) > 1 {
 189  				seg.Data = seg.Data[:offset]
 190  			} else {
 191  				m.removeSegment(index)
 192  			}
 193  		} else {
 194  			newSeg := DataSegment{Address: seg.Address + offset + 1, Data: seg.Data[offset+1:]}
 195  			seg.Data = seg.Data[:offset]
 196  			m.dataSegments = append(m.dataSegments, &newSeg)
 197  		}
 198  	}
 199  	sort.Sort(sortByAddress(m.dataSegments))
 200  }
 201  
 202  func (m *Memory) parseIntelHexRecord(bytes []byte) error {
 203  	if len(bytes) < 5 {
 204  		return newParseError(_DATA_ERROR, "not enought data bytes", m.lineNum)
 205  	}
 206  	err := checkSum(bytes)
 207  	if err != nil {
 208  		return newParseError(_CHECKSUM_ERROR, err.Error(), m.lineNum)
 209  	}
 210  	err = checkRecordSize(bytes)
 211  	if err != nil {
 212  		return newParseError(_DATA_ERROR, err.Error(), m.lineNum)
 213  	}
 214  	switch record_type := bytes[3]; record_type {
 215  	case _DATA_RECORD:
 216  		a, data := getDataLine(bytes)
 217  		adr := uint32(a) + m.extendedAddress
 218  		err = m.AddBinary(adr, data)
 219  		if err != nil {
 220  			return err
 221  		}
 222  	case _EOF_RECORD:
 223  		err = checkEOF(bytes)
 224  		if err != nil {
 225  			return newParseError(_RECORD_ERROR, err.Error(), m.lineNum)
 226  		}
 227  		m.eofFlag = true
 228  	case _ADR_20_RECORD:
 229  		fallthrough
 230  	case _ADR_32_RECORD:
 231  		m.extendedAddress, err = getExtendedAddress(bytes)
 232  		if err != nil {
 233  			return newParseError(_RECORD_ERROR, err.Error(), m.lineNum)
 234  		}
 235  	case _START_RECORD:
 236  		if m.startFlag == true {
 237  			return newParseError(_DATA_ERROR, "multiple start address lines", m.lineNum)
 238  		}
 239  		m.startAddress, err = getStartAddress(bytes)
 240  		if err != nil {
 241  			return newParseError(_RECORD_ERROR, err.Error(), m.lineNum)
 242  		}
 243  		m.startFlag = true
 244  	}
 245  	return nil
 246  }
 247  
 248  func (m *Memory) parseIntelHexLine(line string) error {
 249  	if len(line) == 0 {
 250  		return nil
 251  	}
 252  	if line[0] != ':' {
 253  		return newParseError(_SYNTAX_ERROR, "no colon char on the first line character", m.lineNum)
 254  	}
 255  	bytes, err := hex.DecodeString(line[1:])
 256  	if err != nil {
 257  		return newParseError(_SYNTAX_ERROR, err.Error(), m.lineNum)
 258  	}
 259  	return m.parseIntelHexRecord(bytes)
 260  }
 261  
 262  // Method to parsing IntelHex data and add into memory
 263  func (m *Memory) ParseIntelHex(reader io.Reader) error {
 264  	scanner := bufio.NewScanner(reader)
 265  	m.Clear()
 266  	for scanner.Scan() {
 267  		m.lineNum++
 268  		line := scanner.Text()
 269  		err := m.parseIntelHexLine(line)
 270  		if err != nil {
 271  			return err
 272  		}
 273  	}
 274  	if err := scanner.Err(); err != nil {
 275  		return newParseError(_SYNTAX_ERROR, err.Error(), m.lineNum)
 276  	}
 277  	if m.eofFlag == false {
 278  		return newParseError(_DATA_ERROR, "no end of file line", m.lineNum)
 279  	}
 280  
 281  	return nil
 282  }
 283  
 284  func (m *Memory) dumpDataSegment(writer io.Writer, s *DataSegment, lineLength byte) error {
 285  	lineAdr := s.Address
 286  	lineData := []byte{}
 287  	for byteAdr := s.Address; byteAdr < s.Address+uint32(len(s.Data)); byteAdr++ {
 288  		if ((byteAdr & 0xFFFF0000) != m.extendedAddress) || (m.firstAddressFlag == false) {
 289  			m.firstAddressFlag = true
 290  			if len(lineData) != 0 {
 291  				err := writeDataLine(writer, &lineAdr, byteAdr, &lineData)
 292  				if err != nil {
 293  					return err
 294  				}
 295  			}
 296  			m.extendedAddress = (byteAdr & 0xFFFF0000)
 297  			writeExtendedAddressLine(writer, m.extendedAddress)
 298  		}
 299  		if len(lineData) >= int(lineLength) {
 300  			err := writeDataLine(writer, &lineAdr, byteAdr, &lineData)
 301  			if err != nil {
 302  				return err
 303  			}
 304  		}
 305  		lineData = append(lineData, s.Data[byteAdr-s.Address])
 306  	}
 307  
 308  	if len(lineData) != 0 {
 309  		return writeDataLine(writer, &lineAdr, 0, &lineData)
 310  	}
 311  	return nil
 312  }
 313  
 314  // Method to dumping IntelHex data previously loaded into memory
 315  func (m *Memory) DumpIntelHex(writer io.Writer, lineLength byte) error {
 316  	if m.startFlag {
 317  		err := writeStartAddressLine(writer, m.startAddress)
 318  		if err != nil {
 319  			return err
 320  		}
 321  	}
 322  
 323  	m.firstAddressFlag = false
 324  	m.extendedAddress = 0
 325  	for _, s := range m.dataSegments {
 326  		err := m.dumpDataSegment(writer, s, lineLength)
 327  		if err != nil {
 328  			return err
 329  		}
 330  	}
 331  
 332  	return writeEofLine(writer)
 333  }
 334  
 335  // Method to load binary data previously loaded into memory
 336  func (m *Memory) ToBinary(address uint32, size uint32, padding byte) []byte {
 337  	data := make([]byte, size)
 338  
 339  	i := uint32(0)
 340  	for i < size {
 341  		ok := false
 342  		for _, s := range m.dataSegments {
 343  			if (address >= s.Address) && (address < s.Address+uint32(len(s.Data))) {
 344  				data[i] = s.Data[address-s.Address]
 345  				i++
 346  				address++
 347  				ok = true
 348  				break
 349  			}
 350  		}
 351  		if ok == false {
 352  			data[i] = padding
 353  			i++
 354  			address++
 355  		}
 356  	}
 357  
 358  	return data
 359  }
 360