summaryrefslogtreecommitdiffstats
path: root/common/DataSourceImager.cpp
blob: 14a9307aaf9a5db5236f9aa5d9f5f462f29e7829 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
 * File:	DataSourceImager.cpp
 *
 * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
 * See included license file for license details.
 */

#include "DataSourceImager.h"
#include <stdlib.h>
#include <string.h>

using namespace elftosb;

DataSourceImager::DataSourceImager()
:	Blob(),
	m_fill(0),
	m_baseAddress(0),
	m_isBaseAddressSet(false)
{
}

void DataSourceImager::setBaseAddress(uint32_t address)
{
	m_baseAddress = address;
	m_isBaseAddressSet = true;
}

void DataSourceImager::setFillPattern(uint8_t pattern)
{
	m_fill = pattern;
}

void DataSourceImager::reset()
{
	clear();
	
	m_fill = 0;
	m_baseAddress = 0;
	m_isBaseAddressSet = false;
}

//! \param dataSource Pointer to an instance of a concrete data source subclass.
//!
void DataSourceImager::addDataSource(DataSource * source)
{
	unsigned segmentCount = source->getSegmentCount();
	unsigned index = 0;
	for (; index < segmentCount; ++index)
	{
		addDataSegment(source->getSegmentAt(index));
	}
}

//! \param segment The segment to add. May be any type of data segment, including
//!		a pattern segment.
void DataSourceImager::addDataSegment(DataSource::Segment * segment)
{
	DataSource::PatternSegment * patternSegment = dynamic_cast<DataSource::PatternSegment*>(segment);
	
	unsigned segmentLength = segment->getLength();
	bool segmentHasLocation = segment->hasNaturalLocation();
	uint32_t segmentAddress = segment->getBaseAddress();
	
	uint8_t * toPtr = NULL;
	unsigned addressDelta;
	unsigned newLength;
	
	// If a pattern segment's length is 0 then make it as big as the fill pattern.
	// This needs to be done before the buffer is adjusted.
	if (patternSegment && segmentLength == 0)
	{
		SizedIntegerValue & pattern = patternSegment->getPattern();
		segmentLength = pattern.getSize();
	}
	
	if (segmentLength)
	{
		if (segmentHasLocation)
		{
			// Make sure a base address is set.
			if (!m_isBaseAddressSet)
			{
				m_baseAddress = segmentAddress;
				m_isBaseAddressSet = true;
			}
			
			// The segment is located before our buffer's first address.
			// toPtr is not set in this if, but in the else branch of the next if.
			// Unless the segment completely overwrite the current data.
			if (segmentAddress < m_baseAddress)
			{
				addressDelta = m_baseAddress - segmentAddress;
				
				uint8_t * newData = (uint8_t *)malloc(m_length + addressDelta);
				memcpy(&newData[addressDelta], m_data, m_length);
				free(m_data);
				
				m_data = newData;
				m_length += addressDelta;
				m_baseAddress = segmentAddress;
			}
			
			// This segment is located or extends outside of our buffer.
			if (segmentAddress + segmentLength > m_baseAddress + m_length)
			{
				newLength = segmentAddress + segmentLength - m_baseAddress;
				
				m_data = (uint8_t *)realloc(m_data, newLength);
				
				// Clear any bytes between the old data and the new segment.
				addressDelta = segmentAddress - (m_baseAddress + m_length);
				if (addressDelta)
				{
					memset(m_data + m_length, 0, addressDelta);
				}
				
				toPtr = m_data + (segmentAddress - m_baseAddress);
				m_length = newLength;
			}
			else
			{
				toPtr = m_data + (segmentAddress - m_baseAddress);
			}
		}
		// Segment has no natural location, so just append it to the end of our buffer.
		else
		{
			newLength = m_length + segmentLength;
			m_data = (uint8_t *)realloc(m_data, newLength);
			toPtr = m_data + m_length;
			m_length = newLength;
		}
	}

	// A loop is used because getData() may fill in less than the requested
	// number of bytes per call.
	unsigned offset = 0;
	while (offset < segmentLength)
	{
		offset += segment->getData(offset, segmentLength - offset, toPtr + offset);
	}
}