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