xref: /netbsd-src/external/bsd/elftosb/dist/common/StSRecordFile.cpp (revision 993229b6fea628ff8b1fa09146c80b0cfb2768eb)
1*993229b6Sjkunz /*
2*993229b6Sjkunz  * File:	StSRecordFile.cpp
3*993229b6Sjkunz  *
4*993229b6Sjkunz  * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
5*993229b6Sjkunz  * See included license file for license details.
6*993229b6Sjkunz  */
7*993229b6Sjkunz 
8*993229b6Sjkunz #include "stdafx.h"
9*993229b6Sjkunz #include "StSRecordFile.h"
10*993229b6Sjkunz #include "string.h"
11*993229b6Sjkunz 
StSRecordFile(std::istream & inStream)12*993229b6Sjkunz StSRecordFile::StSRecordFile(std::istream & inStream)
13*993229b6Sjkunz :	m_stream(inStream)
14*993229b6Sjkunz {
15*993229b6Sjkunz }
16*993229b6Sjkunz 
17*993229b6Sjkunz //! Frees any data allocated as part of an S-record.
~StSRecordFile()18*993229b6Sjkunz StSRecordFile::~StSRecordFile()
19*993229b6Sjkunz {
20*993229b6Sjkunz 	const_iterator it;
21*993229b6Sjkunz 	for (it = m_records.begin(); it != m_records.end(); it++)
22*993229b6Sjkunz 	{
23*993229b6Sjkunz 		SRecord & theRecord = (SRecord &)*it;
24*993229b6Sjkunz 		if (theRecord.m_data)
25*993229b6Sjkunz 		{
26*993229b6Sjkunz 			delete [] theRecord.m_data;
27*993229b6Sjkunz 			theRecord.m_data = NULL;
28*993229b6Sjkunz 		}
29*993229b6Sjkunz 	}
30*993229b6Sjkunz }
31*993229b6Sjkunz 
32*993229b6Sjkunz //! Just looks for "S[0-9]" as the first two characters of the file.
isSRecordFile()33*993229b6Sjkunz bool StSRecordFile::isSRecordFile()
34*993229b6Sjkunz {
35*993229b6Sjkunz 	int savePosition = m_stream.tellg();
36*993229b6Sjkunz 	m_stream.seekg(0, std::ios_base::beg);
37*993229b6Sjkunz 
38*993229b6Sjkunz 	char buffer[2];
39*993229b6Sjkunz 	m_stream.read(buffer, 2);
40*993229b6Sjkunz 	bool isSRecord = (buffer[0] == 'S' && isdigit(buffer[1]));
41*993229b6Sjkunz 
42*993229b6Sjkunz 	m_stream.seekg(savePosition, std::ios_base::beg);
43*993229b6Sjkunz 
44*993229b6Sjkunz 	return isSRecord;
45*993229b6Sjkunz }
46*993229b6Sjkunz 
47*993229b6Sjkunz //! Extract records one line at a time and hand them to the parseLine()
48*993229b6Sjkunz //! method. Either CR, LF, or CRLF line endings are supported. The input
49*993229b6Sjkunz //! stream is read until EOF.
50*993229b6Sjkunz //! The parse() method must be called after the object has been constructed
51*993229b6Sjkunz //! before any of the records will become accessible.
52*993229b6Sjkunz //! \exception StSRecordParseException will be thrown if any error occurs while
53*993229b6Sjkunz //!		parsing the input.
parse()54*993229b6Sjkunz void StSRecordFile::parse()
55*993229b6Sjkunz {
56*993229b6Sjkunz 	// back to start of stream
57*993229b6Sjkunz 	m_stream.seekg(0, std::ios_base::beg);
58*993229b6Sjkunz 
59*993229b6Sjkunz 	std::string thisLine;
60*993229b6Sjkunz 
61*993229b6Sjkunz 	do {
62*993229b6Sjkunz 		char thisChar;
63*993229b6Sjkunz 		m_stream.get(thisChar);
64*993229b6Sjkunz 
65*993229b6Sjkunz 		if (thisChar == '\r' || thisChar == '\n')
66*993229b6Sjkunz 		{
67*993229b6Sjkunz 			// skip the LF in a CRLF
68*993229b6Sjkunz 			if (thisChar == '\r' && m_stream.peek() == '\n')
69*993229b6Sjkunz 				m_stream.ignore();
70*993229b6Sjkunz 
71*993229b6Sjkunz 			// parse line if it's not empty
72*993229b6Sjkunz 			if (!thisLine.empty())
73*993229b6Sjkunz 			{
74*993229b6Sjkunz 				parseLine(thisLine);
75*993229b6Sjkunz 
76*993229b6Sjkunz 				// reset line
77*993229b6Sjkunz 				thisLine.clear();
78*993229b6Sjkunz 			}
79*993229b6Sjkunz 		}
80*993229b6Sjkunz 		else
81*993229b6Sjkunz 		{
82*993229b6Sjkunz 			thisLine += thisChar;
83*993229b6Sjkunz 		}
84*993229b6Sjkunz 	} while (!m_stream.eof());
85*993229b6Sjkunz }
86*993229b6Sjkunz 
isHexDigit(char c)87*993229b6Sjkunz bool StSRecordFile::isHexDigit(char c)
88*993229b6Sjkunz {
89*993229b6Sjkunz 	return (isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
90*993229b6Sjkunz }
91*993229b6Sjkunz 
hexDigitToInt(char digit)92*993229b6Sjkunz int StSRecordFile::hexDigitToInt(char digit)
93*993229b6Sjkunz {
94*993229b6Sjkunz 	if (isdigit(digit))
95*993229b6Sjkunz 		return digit - '0';
96*993229b6Sjkunz 	else if (digit >= 'a' && digit <= 'f')
97*993229b6Sjkunz 		return 10 + digit - 'a';
98*993229b6Sjkunz 	else if (digit >= 'A' && digit <= 'F')
99*993229b6Sjkunz 		return 10 + digit - 'A';
100*993229b6Sjkunz 
101*993229b6Sjkunz 	// unknow char
102*993229b6Sjkunz 	return 0;
103*993229b6Sjkunz }
104*993229b6Sjkunz 
105*993229b6Sjkunz //! \exception StSRecordParseException is thrown if either of the nibble characters
106*993229b6Sjkunz //!		is not a valid hex digit.
readHexByte(std::string & inString,int inIndex)107*993229b6Sjkunz int StSRecordFile::readHexByte(std::string & inString, int inIndex)
108*993229b6Sjkunz {
109*993229b6Sjkunz 	char nibbleCharHi= inString[inIndex];
110*993229b6Sjkunz 	char nibbleCharLo = inString[inIndex + 1];
111*993229b6Sjkunz 
112*993229b6Sjkunz 	// must be hex digits
113*993229b6Sjkunz 	if (!(isHexDigit(nibbleCharHi) && isHexDigit(nibbleCharLo)))
114*993229b6Sjkunz     {
115*993229b6Sjkunz 		throw StSRecordParseException("invalid hex digit");
116*993229b6Sjkunz     }
117*993229b6Sjkunz 
118*993229b6Sjkunz 	return (hexDigitToInt(nibbleCharHi) << 4) | hexDigitToInt(nibbleCharLo);
119*993229b6Sjkunz }
120*993229b6Sjkunz 
121*993229b6Sjkunz //! \brief Parses individual S-records.
122*993229b6Sjkunz //!
123*993229b6Sjkunz //! Takes a single S-record line as input and appends a new SRecord struct
124*993229b6Sjkunz //! to the m_records vector.
125*993229b6Sjkunz //! \exception StSRecordParseException will be thrown if any error occurs while
126*993229b6Sjkunz //!		parsing \a inLine.
parseLine(std::string & inLine)127*993229b6Sjkunz void StSRecordFile::parseLine(std::string & inLine)
128*993229b6Sjkunz {
129*993229b6Sjkunz 	int checksum = 0;
130*993229b6Sjkunz 	SRecord newRecord;
131*993229b6Sjkunz 	memset(&newRecord, 0, sizeof(newRecord));
132*993229b6Sjkunz 
133*993229b6Sjkunz 	// must start with "S" and be at least a certain length
134*993229b6Sjkunz 	if (inLine[0] != SRECORD_START_CHAR && inLine.length() >= SRECORD_MIN_LENGTH)
135*993229b6Sjkunz     {
136*993229b6Sjkunz         throw StSRecordParseException("invalid record length");
137*993229b6Sjkunz     }
138*993229b6Sjkunz 
139*993229b6Sjkunz 	// parse type field
140*993229b6Sjkunz 	char typeChar = inLine[1];
141*993229b6Sjkunz 	if (!isdigit(typeChar))
142*993229b6Sjkunz     {
143*993229b6Sjkunz 		throw StSRecordParseException("invalid S-record type");
144*993229b6Sjkunz     }
145*993229b6Sjkunz 	newRecord.m_type = typeChar - '0';
146*993229b6Sjkunz 
147*993229b6Sjkunz 	// parse count field
148*993229b6Sjkunz 	newRecord.m_count = readHexByte(inLine, 2);
149*993229b6Sjkunz 	checksum += newRecord.m_count;
150*993229b6Sjkunz 
151*993229b6Sjkunz 	// verify the record length now that we know the count
152*993229b6Sjkunz 	if (inLine.length() != 4 + newRecord.m_count * 2)
153*993229b6Sjkunz     {
154*993229b6Sjkunz 		throw StSRecordParseException("invalid record length");
155*993229b6Sjkunz     }
156*993229b6Sjkunz 
157*993229b6Sjkunz 	// get address length
158*993229b6Sjkunz 	int addressLength;	// len in bytes
159*993229b6Sjkunz 	bool hasData = false;
160*993229b6Sjkunz 	switch (newRecord.m_type)
161*993229b6Sjkunz 	{
162*993229b6Sjkunz 		case 0:     // contains header information
163*993229b6Sjkunz 			addressLength = 2;
164*993229b6Sjkunz 			hasData = true;
165*993229b6Sjkunz 			break;
166*993229b6Sjkunz 		case 1:     // data record with 2-byte address
167*993229b6Sjkunz 			addressLength = 2;
168*993229b6Sjkunz 			hasData = true;
169*993229b6Sjkunz 			break;
170*993229b6Sjkunz 		case 2:     // data record with 3-byte address
171*993229b6Sjkunz 			addressLength = 3;
172*993229b6Sjkunz 			hasData = true;
173*993229b6Sjkunz 			break;
174*993229b6Sjkunz 		case 3:     // data record with 4-byte address
175*993229b6Sjkunz 			addressLength = 4;
176*993229b6Sjkunz 			hasData = true;
177*993229b6Sjkunz 			break;
178*993229b6Sjkunz 		case 5:     // the 2-byte address field contains a count of all prior S1, S2, and S3 records
179*993229b6Sjkunz 			addressLength = 2;
180*993229b6Sjkunz 			break;
181*993229b6Sjkunz 		case 7:     // entry point record with 4-byte address
182*993229b6Sjkunz 			addressLength = 4;
183*993229b6Sjkunz 			break;
184*993229b6Sjkunz 		case 8:     // entry point record with 3-byte address
185*993229b6Sjkunz 			addressLength = 3;
186*993229b6Sjkunz 			break;
187*993229b6Sjkunz 		case 9:     // entry point record with 2-byte address
188*993229b6Sjkunz 			addressLength = 2;
189*993229b6Sjkunz 			break;
190*993229b6Sjkunz 		default:
191*993229b6Sjkunz 			// unrecognized type
192*993229b6Sjkunz 			//throw StSRecordParseException("unknown S-record type");
193*993229b6Sjkunz             break;
194*993229b6Sjkunz 	}
195*993229b6Sjkunz 
196*993229b6Sjkunz 	// read address
197*993229b6Sjkunz 	int address = 0;
198*993229b6Sjkunz 	int i;
199*993229b6Sjkunz 	for (i=0; i < addressLength; ++i)
200*993229b6Sjkunz 	{
201*993229b6Sjkunz 		int addressByte = readHexByte(inLine, SRECORD_ADDRESS_START_CHAR_INDEX + i * 2);
202*993229b6Sjkunz 		address = (address << 8) | addressByte;
203*993229b6Sjkunz 		checksum += addressByte;
204*993229b6Sjkunz 	}
205*993229b6Sjkunz 	newRecord.m_address = address;
206*993229b6Sjkunz 
207*993229b6Sjkunz 	// read data
208*993229b6Sjkunz 	if (hasData)
209*993229b6Sjkunz 	{
210*993229b6Sjkunz 		int dataStartCharIndex = 4 + addressLength * 2;
211*993229b6Sjkunz 		int dataLength = newRecord.m_count - addressLength - 1; // total rem - addr - cksum (in bytes)
212*993229b6Sjkunz 		uint8_t * data = new uint8_t[dataLength];
213*993229b6Sjkunz 
214*993229b6Sjkunz 		for (i=0; i < dataLength; ++i)
215*993229b6Sjkunz 		{
216*993229b6Sjkunz 			int dataByte = readHexByte(inLine, dataStartCharIndex + i * 2);
217*993229b6Sjkunz 			data[i] = dataByte;
218*993229b6Sjkunz 			checksum += dataByte;
219*993229b6Sjkunz 		}
220*993229b6Sjkunz 
221*993229b6Sjkunz 		newRecord.m_data = data;
222*993229b6Sjkunz 		newRecord.m_dataCount = dataLength;
223*993229b6Sjkunz 	}
224*993229b6Sjkunz 
225*993229b6Sjkunz 	// read and compare checksum byte
226*993229b6Sjkunz 	checksum = (~checksum) & 0xff;	// low byte of one's complement of sum of other bytes
227*993229b6Sjkunz 	newRecord.m_checksum = readHexByte(inLine, (int)inLine.length() - 2);
228*993229b6Sjkunz 	if (checksum != newRecord.m_checksum)
229*993229b6Sjkunz     {
230*993229b6Sjkunz 		throw StSRecordParseException("invalid checksum");
231*993229b6Sjkunz     }
232*993229b6Sjkunz 
233*993229b6Sjkunz 	// now save the new S-record
234*993229b6Sjkunz 	m_records.push_back(newRecord);
235*993229b6Sjkunz }
236