1/*
2 * File:	DataSourceImager.cpp
3 *
4 * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
5 * See included license file for license details.
6 */
7
8#include "DataSourceImager.h"
9#include <stdlib.h>
10#include <string.h>
11
12using namespace elftosb;
13
14DataSourceImager::DataSourceImager()
15:	Blob(),
16	m_fill(0),
17	m_baseAddress(0),
18	m_isBaseAddressSet(false)
19{
20}
21
22void DataSourceImager::setBaseAddress(uint32_t address)
23{
24	m_baseAddress = address;
25	m_isBaseAddressSet = true;
26}
27
28void DataSourceImager::setFillPattern(uint8_t pattern)
29{
30	m_fill = pattern;
31}
32
33void DataSourceImager::reset()
34{
35	clear();
36
37	m_fill = 0;
38	m_baseAddress = 0;
39	m_isBaseAddressSet = false;
40}
41
42//! \param dataSource Pointer to an instance of a concrete data source subclass.
43//!
44void DataSourceImager::addDataSource(DataSource * source)
45{
46	unsigned segmentCount = source->getSegmentCount();
47	unsigned index = 0;
48	for (; index < segmentCount; ++index)
49	{
50		addDataSegment(source->getSegmentAt(index));
51	}
52}
53
54//! \param segment The segment to add. May be any type of data segment, including
55//!		a pattern segment.
56void DataSourceImager::addDataSegment(DataSource::Segment * segment)
57{
58	DataSource::PatternSegment * patternSegment = dynamic_cast<DataSource::PatternSegment*>(segment);
59
60	unsigned segmentLength = segment->getLength();
61	bool segmentHasLocation = segment->hasNaturalLocation();
62	uint32_t segmentAddress = segment->getBaseAddress();
63
64	uint8_t * toPtr = NULL;
65	unsigned addressDelta;
66	unsigned newLength;
67
68	// If a pattern segment's length is 0 then make it as big as the fill pattern.
69	// This needs to be done before the buffer is adjusted.
70	if (patternSegment && segmentLength == 0)
71	{
72		SizedIntegerValue & pattern = patternSegment->getPattern();
73		segmentLength = pattern.getSize();
74	}
75
76	if (segmentLength)
77	{
78		if (segmentHasLocation)
79		{
80			// Make sure a base address is set.
81			if (!m_isBaseAddressSet)
82			{
83				m_baseAddress = segmentAddress;
84				m_isBaseAddressSet = true;
85			}
86
87			// The segment is located before our buffer's first address.
88			// toPtr is not set in this if, but in the else branch of the next if.
89			// Unless the segment completely overwrite the current data.
90			if (segmentAddress < m_baseAddress)
91			{
92				addressDelta = m_baseAddress - segmentAddress;
93
94				uint8_t * newData = (uint8_t *)malloc(m_length + addressDelta);
95				memcpy(&newData[addressDelta], m_data, m_length);
96				free(m_data);
97
98				m_data = newData;
99				m_length += addressDelta;
100				m_baseAddress = segmentAddress;
101			}
102
103			// This segment is located or extends outside of our buffer.
104			if (segmentAddress + segmentLength > m_baseAddress + m_length)
105			{
106				newLength = segmentAddress + segmentLength - m_baseAddress;
107
108				m_data = (uint8_t *)realloc(m_data, newLength);
109
110				// Clear any bytes between the old data and the new segment.
111				addressDelta = segmentAddress - (m_baseAddress + m_length);
112				if (addressDelta)
113				{
114					memset(m_data + m_length, 0, addressDelta);
115				}
116
117				toPtr = m_data + (segmentAddress - m_baseAddress);
118				m_length = newLength;
119			}
120			else
121			{
122				toPtr = m_data + (segmentAddress - m_baseAddress);
123			}
124		}
125		// Segment has no natural location, so just append it to the end of our buffer.
126		else
127		{
128			newLength = m_length + segmentLength;
129			m_data = (uint8_t *)realloc(m_data, newLength);
130			toPtr = m_data + m_length;
131			m_length = newLength;
132		}
133	}
134
135	// A loop is used because getData() may fill in less than the requested
136	// number of bytes per call.
137	unsigned offset = 0;
138	while (offset < segmentLength)
139	{
140		offset += segment->getData(offset, segmentLength - offset, toPtr + offset);
141	}
142}
143
144