xref: /netbsd-src/external/bsd/elftosb/dist/common/DataSourceImager.cpp (revision 993229b6fea628ff8b1fa09146c80b0cfb2768eb)
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 
12 using namespace elftosb;
13 
DataSourceImager()14 DataSourceImager::DataSourceImager()
15 :	Blob(),
16 	m_fill(0),
17 	m_baseAddress(0),
18 	m_isBaseAddressSet(false)
19 {
20 }
21 
setBaseAddress(uint32_t address)22 void DataSourceImager::setBaseAddress(uint32_t address)
23 {
24 	m_baseAddress = address;
25 	m_isBaseAddressSet = true;
26 }
27 
setFillPattern(uint8_t pattern)28 void DataSourceImager::setFillPattern(uint8_t pattern)
29 {
30 	m_fill = pattern;
31 }
32 
reset()33 void 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 //!
addDataSource(DataSource * source)44 void 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.
addDataSegment(DataSource::Segment * segment)56 void 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