2 * File: StSRecordFile.cpp
4 * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
5 * See included license file for license details.
9 #include "StSRecordFile.h"
12 StSRecordFile::StSRecordFile(std::istream & inStream)
17 //! Frees any data allocated as part of an S-record.
18 StSRecordFile::~StSRecordFile()
21 for (it = m_records.begin(); it != m_records.end(); it++)
23 SRecord & theRecord = (SRecord &)*it;
26 delete [] theRecord.m_data;
27 theRecord.m_data = NULL;
32 //! Just looks for "S[0-9]" as the first two characters of the file.
33 bool StSRecordFile::isSRecordFile()
35 int savePosition = m_stream.tellg();
36 m_stream.seekg(0, std::ios_base::beg);
39 m_stream.read(buffer, 2);
40 bool isSRecord = (buffer[0] == 'S' && isdigit(buffer[1]));
42 m_stream.seekg(savePosition, std::ios_base::beg);
47 //! Extract records one line at a time and hand them to the parseLine()
48 //! method. Either CR, LF, or CRLF line endings are supported. The input
49 //! stream is read until EOF.
50 //! The parse() method must be called after the object has been constructed
51 //! before any of the records will become accessible.
52 //! \exception StSRecordParseException will be thrown if any error occurs while
53 //! parsing the input.
54 void StSRecordFile::parse()
56 // back to start of stream
57 m_stream.seekg(0, std::ios_base::beg);
63 m_stream.get(thisChar);
65 if (thisChar == '\r' || thisChar == '\n')
67 // skip the LF in a CRLF
68 if (thisChar == '\r' && m_stream.peek() == '\n')
71 // parse line if it's not empty
72 if (!thisLine.empty())
84 } while (!m_stream.eof());
87 bool StSRecordFile::isHexDigit(char c)
89 return (isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
92 int StSRecordFile::hexDigitToInt(char digit)
96 else if (digit >= 'a' && digit <= 'f')
97 return 10 + digit - 'a';
98 else if (digit >= 'A' && digit <= 'F')
99 return 10 + digit - 'A';
105 //! \exception StSRecordParseException is thrown if either of the nibble characters
106 //! is not a valid hex digit.
107 int StSRecordFile::readHexByte(std::string & inString, int inIndex)
109 char nibbleCharHi= inString[inIndex];
110 char nibbleCharLo = inString[inIndex + 1];
112 // must be hex digits
113 if (!(isHexDigit(nibbleCharHi) && isHexDigit(nibbleCharLo)))
115 throw StSRecordParseException("invalid hex digit");
118 return (hexDigitToInt(nibbleCharHi) << 4) | hexDigitToInt(nibbleCharLo);
121 //! \brief Parses individual S-records.
123 //! Takes a single S-record line as input and appends a new SRecord struct
124 //! to the m_records vector.
125 //! \exception StSRecordParseException will be thrown if any error occurs while
126 //! parsing \a inLine.
127 void StSRecordFile::parseLine(std::string & inLine)
131 memset(&newRecord, 0, sizeof(newRecord));
133 // must start with "S" and be at least a certain length
134 if (inLine[0] != SRECORD_START_CHAR && inLine.length() >= SRECORD_MIN_LENGTH)
136 throw StSRecordParseException("invalid record length");
140 char typeChar = inLine[1];
141 if (!isdigit(typeChar))
143 throw StSRecordParseException("invalid S-record type");
145 newRecord.m_type = typeChar - '0';
148 newRecord.m_count = readHexByte(inLine, 2);
149 checksum += newRecord.m_count;
151 // verify the record length now that we know the count
152 if (inLine.length() != 4 + newRecord.m_count * 2)
154 throw StSRecordParseException("invalid record length");
157 // get address length
158 int addressLength; // len in bytes
159 bool hasData = false;
160 switch (newRecord.m_type)
162 case 0: // contains header information
166 case 1: // data record with 2-byte address
170 case 2: // data record with 3-byte address
174 case 3: // data record with 4-byte address
178 case 5: // the 2-byte address field contains a count of all prior S1, S2, and S3 records
181 case 7: // entry point record with 4-byte address
184 case 8: // entry point record with 3-byte address
187 case 9: // entry point record with 2-byte address
192 //throw StSRecordParseException("unknown S-record type");
199 for (i=0; i < addressLength; ++i)
201 int addressByte = readHexByte(inLine, SRECORD_ADDRESS_START_CHAR_INDEX + i * 2);
202 address = (address << 8) | addressByte;
203 checksum += addressByte;
205 newRecord.m_address = address;
210 int dataStartCharIndex = 4 + addressLength * 2;
211 int dataLength = newRecord.m_count - addressLength - 1; // total rem - addr - cksum (in bytes)
212 uint8_t * data = new uint8_t[dataLength];
214 for (i=0; i < dataLength; ++i)
216 int dataByte = readHexByte(inLine, dataStartCharIndex + i * 2);
218 checksum += dataByte;
221 newRecord.m_data = data;
222 newRecord.m_dataCount = dataLength;
225 // read and compare checksum byte
226 checksum = (~checksum) & 0xff; // low byte of one's complement of sum of other bytes
227 newRecord.m_checksum = readHexByte(inLine, (int)inLine.length() - 2);
228 if (checksum != newRecord.m_checksum)
230 throw StSRecordParseException("invalid checksum");
233 // now save the new S-record
234 m_records.push_back(newRecord);